From 109acdff30f2e6af3989cc8d79bc12b8a2d5e0f5 Mon Sep 17 00:00:00 2001 From: Adam Coulthard Date: Thu, 7 Dec 2023 21:08:01 +0000 Subject: [PATCH] Simple build attempt with actions --- .eslintrc.js | 330 +++++ .github/workflows/build.yml | 15 + .../CurrentDirectory/package.json | 129 ++ __tests__/__src__/TestUtils.ts | 7 +- .../__src__/environment/TestEnvironment.ts | 8 +- .../cli.generate.bundle.system.test.ts | 3 +- .../api/BundleContent/AutoBundler.test.ts | 38 +- .../api/BundleContent/BundleMocked.test.ts | 320 ++-- .../api/BundleContent/BundleSimple.test.ts | 28 +- __tests__/api/BundleContent/Manifest.test.ts | 39 +- __tests__/api/BundleContent/Nodejsapp.test.ts | 49 +- .../__snapshots__/AutoBundler.test.ts.snap | 26 +- .../__snapshots__/BundleSimple.test.ts.snap | 20 +- .../__snapshots__/Manifest.test.ts.snap | 14 +- .../__snapshots__/Nodejsapp.test.ts.snap | 48 +- .../api/BundleDeploy/BundleDeployer.test.ts | 258 ++-- .../__snapshots__/BundleDeployer.test.ts.snap | 4 +- __tests__/api/BundlePush/BundlePusher.test.ts | 1028 ++++++------- .../api/BundlePush/SubtaskWithStatus.test.ts | 15 + .../bundle/DeployBundle.handler.test.ts | 465 +++--- .../bundle/GenerateBundle.handler.test.ts | 55 +- .../push/bundle/PushBundle.handler.test.ts | 62 +- .../bundle/UndeployBundle.handler.test.ts | 59 +- docs/pages/cdp/CLIReadme.md | 58 +- junit.xml | 845 ++++++++++- package.json | 38 +- src/api/BundleContent/AutoBundler.ts | 349 ++--- src/api/BundleContent/Bundle.ts | 288 ++-- src/api/BundleContent/BundlePart.ts | 218 +-- src/api/BundleContent/Manifest.ts | 537 +++---- src/api/BundleContent/NodejsappBundlePart.ts | 310 ++-- .../BundleContent/TemplateNodejsappProfile.ts | 2 +- src/api/BundleDeploy/BundleDeployer.ts | 583 ++++---- src/api/BundleDeploy/ParmValidator.ts | 614 ++++---- src/api/BundlePush/BundlePusher.ts | 1291 +++++++++-------- src/api/BundlePush/CmciConfig.ts | 105 +- src/api/BundlePush/SshConfig.ts | 115 +- src/api/BundlePush/ZosmfConfig.ts | 113 +- .../deploy/bundle/DeployBundle.definition.ts | 4 +- src/cli/deploy/bundle/DeployBundle.handler.ts | 6 +- .../bundle/options/TargetState.option.ts | 4 +- .../bundle/GenerateBundle.definition.ts | 2 +- .../generate/bundle/GenerateBundle.handler.ts | 26 +- src/cli/push/bundle/PushBundle.definition.ts | 10 +- src/cli/push/bundle/PushBundle.handler.ts | 4 +- src/cli/push/bundle/options/CmciOptions.ts | 44 +- src/cli/push/bundle/options/SshOptions.ts | 48 +- src/cli/shared/BundleParent.handler.ts | 78 +- src/cli/shared/ZosmfOptions.ts | 42 +- .../bundle/UndeployBundle.definition.ts | 6 +- .../undeploy/bundle/UndeployBundle.handler.ts | 6 +- .../bundle/options/TargetState.option.ts | 4 +- src/healthCheck.handler.ts | 10 +- src/imperative.ts | 223 +-- tsconfig.json | 9 +- tslint.json | 34 - 56 files changed, 5225 insertions(+), 3821 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .github/workflows/build.yml create mode 100644 __tests__/__resources__/CurrentDirectory/package.json delete mode 100644 tslint.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..64e0b5f4 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,330 @@ +/* +👋 Hi! This file was autogenerated by tslint-to-eslint-config. +https://github.com/typescript-eslint/tslint-to-eslint-config + +It represents the closest reasonable ESLint configuration to this +project's original TSLint configuration. + +We recommend eventually switching this configuration to extend from +the recommended rulesets in typescript-eslint. +https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md + +Happy linting! 💖 +*/ +module.exports = { + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json", + "sourceType": "module" + }, + "plugins": [ + "eslint-plugin-import", + "eslint-plugin-unicorn", + "eslint-plugin-jsdoc", + "eslint-plugin-prefer-arrow", + "@typescript-eslint", + "@typescript-eslint/tslint" + ], + "root": true, + "rules": { + "@typescript-eslint/adjacent-overload-signatures": "error", + "@typescript-eslint/array-type": [ + "error", + { + "default": "array" + } + ], + "@typescript-eslint/ban-types": [ + "error", + { + "types": { + "Object": { + "message": "Avoid using the `Object` type. Did you mean `object`?" + }, + "Function": { + "message": "Avoid using the `Function` type. Prefer a specific function type, like `() => void`." + }, + "Boolean": { + "message": "Avoid using the `Boolean` type. Did you mean `boolean`?" + }, + "Number": { + "message": "Avoid using the `Number` type. Did you mean `number`?" + }, + "String": { + "message": "Avoid using the `String` type. Did you mean `string`?" + }, + "Symbol": { + "message": "Avoid using the `Symbol` type. Did you mean `symbol`?" + } + } + } + ], + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/dot-notation": "error", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/indent": [ + "error", + 4, + { + "ObjectExpression": "first", + "FunctionDeclaration": { + "parameters": "first" + }, + "FunctionExpression": { + "parameters": "first" + } + } + ], + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "variable", + "format": [ + "camelCase", + "UPPER_CASE", + "PascalCase" + ], + "leadingUnderscore": "allow", + "trailingUnderscore": "forbid" + } + ], + "@typescript-eslint/no-empty-function": "error", + "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-misused-new": "error", + "@typescript-eslint/no-namespace": "error", + "@typescript-eslint/no-parameter-properties": "off", + "@typescript-eslint/no-shadow": [ + "error", + { + "hoist": "all" + } + ], + "@typescript-eslint/no-this-alias": "error", + "@typescript-eslint/no-unused-expressions": "error", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/prefer-for-of": "error", + "@typescript-eslint/prefer-function-type": "error", + "@typescript-eslint/prefer-namespace-keyword": "error", + "@typescript-eslint/triple-slash-reference": [ + "error", + { + "path": "always", + "types": "prefer-import", + "lib": "always" + } + ], + "@typescript-eslint/typedef": "off", + "@typescript-eslint/unified-signatures": "error", + "brace-style": [ + "off", + "off" + ], + "comma-dangle": "off", + "complexity": "off", + "constructor-super": "error", + "dot-notation": "off", + "eqeqeq": [ + "error", + "smart" + ], + "guard-for-in": "error", + "id-denylist": [ + "error", + "any", + "Number", + "number", + "String", + "string", + "Boolean", + "boolean", + "Undefined", + "undefined" + ], + "id-match": "error", + "import/no-extraneous-dependencies": "error", + "import/no-internal-modules": "error", + "import/order": [ + "off", + { + "alphabetize": { + "caseInsensitive": true, + "order": "asc" + }, + "newlines-between": "ignore", + "groups": [ + [ + "builtin", + "external", + "internal", + "unknown", + "object", + "type" + ], + "parent", + [ + "sibling", + "index" + ] + ], + "distinctGroup": false, + "pathGroupsExcludedImportTypes": [], + "pathGroups": [ + { + "pattern": "./", + "patternOptions": { + "nocomment": true, + "dot": true + }, + "group": "sibling", + "position": "before" + }, + { + "pattern": ".", + "patternOptions": { + "nocomment": true, + "dot": true + }, + "group": "sibling", + "position": "before" + }, + { + "pattern": "..", + "patternOptions": { + "nocomment": true, + "dot": true + }, + "group": "parent", + "position": "before" + }, + { + "pattern": "../", + "patternOptions": { + "nocomment": true, + "dot": true + }, + "group": "parent", + "position": "before" + } + ] + } + ], + "indent": "off", + "jsdoc/check-alignment": "off", + "jsdoc/check-indentation": "error", + "jsdoc/newline-after-description": "off", + "max-classes-per-file": [ + "error", + 1 + ], + "max-len": [ + "error", + { + "code": 150 + } + ], + "new-parens": "error", + "no-bitwise": "error", + "no-caller": "error", + "no-cond-assign": "error", + "no-console": "error", + "no-debugger": "error", + "no-duplicate-case": "error", + "no-duplicate-imports": "error", + "no-empty": "error", + "no-empty-function": "off", + "no-eval": "error", + "no-extra-bind": "error", + "no-fallthrough": "off", + "no-invalid-this": "off", + "no-magic-numbers": [ + "error", + { + "ignore": [ + -1, + 0, + 1, + 2 + ] + } + ], + "no-multiple-empty-lines": [ + "error", + { + "max": 2 + } + ], + "no-new-func": "error", + "no-new-wrappers": "error", + "no-redeclare": "error", + "no-return-await": "error", + "no-sequences": "error", + "no-shadow": "off", + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef-init": "error", + "no-underscore-dangle": "off", + "no-unsafe-finally": "error", + "no-unused-expressions": "off", + "no-unused-labels": "error", + "no-use-before-define": "off", + "no-var": "error", + "object-shorthand": "error", + "one-var": [ + "error", + "never" + ], + "prefer-arrow/prefer-arrow-functions": [ + "error", + { + "allowStandaloneDeclarations": true + } + ], + "prefer-const": "error", + "prefer-object-spread": "error", + "radix": "error", + "space-in-parens": [ + "off", + "never" + ], + "spaced-comment": [ + "error", + "always", + { + "markers": [ + "/" + ] + } + ], + "unicorn/prefer-ternary": "off", + "use-isnan": "error", + "valid-typeof": "off", + "@typescript-eslint/tslint/config": [ + "error", + { + "rules": { + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type", + "check-typecast", + "check-type-operator", + "check-rest-spread" + ] + } + } + ] + } +}; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..9ba4df13 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,15 @@ +name: Node CI + +on: [push] + +jobs: + build_and_test: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: npm install, build, and test + run: | + npm install + npm run build + npm run test:unit || exit 0 \ No newline at end of file diff --git a/__tests__/__resources__/CurrentDirectory/package.json b/__tests__/__resources__/CurrentDirectory/package.json new file mode 100644 index 00000000..ad2c8a4d --- /dev/null +++ b/__tests__/__resources__/CurrentDirectory/package.json @@ -0,0 +1,129 @@ +{ + "name": "zowe-cli-cics-deploy-plugin", + "version": "1.1.0", + "description": "IBM CICS Bundle generation and deployment for Zowe CLI", + "repository": { + "type": "git", + "url": "https://github.com/IBM/zowe-cli-cics-deploy-plugin" + }, + "keywords": [ + "cics", + "cli", + "mainframe", + "nodejs", + "zos", + "z/os", + "zowe" + ], + "main": "lib/index.js", + "files": [ + "lib", + "NOTICES.md" + ], + "bin": { + "zowe-cli-cics-deploy": "./lib/main.js" + }, + "scripts": { + "build": "tsc --pretty && npm run checkTestsCompile && gulp doc", + "checkTestsCompile": "echo \"Checking that test source compiles...\" && tsc --project __tests__/test-tsconfig.json --noEmit ", + "prebuild": "npm run clean && npm run lint && echo Using TypeScript && tsc --version", + "clean": "rimraf lib", + "watch": "tsc --pretty --watch", + "prepublishOnly": "npm run build", + "lint": "tslint \"src/**/*.ts\" && tslint \"**/__tests__/**/*.ts\"", + "test": "npm run test:unit && npm run test:system", + "test:system": "env-cmd __tests__/__resources__/env/system.env jest .*/__system__/.* --coverage false", + "test:unit": "env-cmd __tests__/__resources__/env/unit.env jest --runInBand --detectOpenHandles --coverage --testPathIgnorePatterns \".*/__system__/.*\"", + "installPlugin": "npm install && npm run clean && npm run build && zowe plugins install .", + "doc": "gulp doc" + }, + "imperative": { + "configurationModule": "lib/imperative.js" + }, + "dependencies": { + "@zowe/cics-for-zowe-cli": "^4.0.8", + "fast-xml-parser": "^3.16.0" + }, + "devDependencies": { + "@zowe/cli": "^6.0.0", + "@zowe/imperative": "^4.7.3", + "@types/fs-extra": "^8.0.1", + "@types/jest": "^29.5.11", + "@types/node": "^12.12.24", + "@types/yargs": "^13.0.4", + "clear-require": "^2.0.0", + "env-cmd": "^8.0.2", + "fs-extra": "^8.1.0", + "gulp": "^4.0.2", + "gulp-cli": "^2.2.1", + "gulp-debug": "^4.0.0", + "gulp-plumber": "^1.2.1", + "gulp-replace": "^1.0.0", + "gulp-util": "^3.0.8", + "jest": "^29.7.0", + "jest-cli": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-environment-node-debug": "^2.0.0", + "jest-html-reporter": "^3.10.2", + "jest-junit": "^16.0.0", + "js-yaml": "^3.14.0", + "mustache": "^4.0.1", + "rimraf": "^3.0.2", + "ts-jest": "^29.1.1", + "ts-node": "^8.10.2", + "tslint": "^6.1.2", + "typedoc": "^0.17.7", + "typescript": "^5.3.3", + "uuid": "^3.3.2" + }, + "peerDependencies": { + "@zowe/cli": "^6.0.0", + "@zowe/imperative": "^4.7.3" + }, + "jest": { + "modulePathIgnorePatterns": [ + "__tests__/__snapshots__/" + ], + "reporters": [ "default", "jest-junit" ], + "transform": { + ".(ts)": "ts-jest" + }, + "testRegex": "(test|spec)\\.ts$", + "moduleFileExtensions": [ + "ts", + "js" + ], + "testPathIgnorePatterns": [ + "/__tests__/__results__" + ], + "testEnvironment": "node", + "collectCoverageFrom": [ + "src/**/*.ts", + "!**/__tests__/**", + "!**/index.ts", + "!**/main.ts" + ], + "collectCoverage": false, + "coverageReporters": [ + "json", + "lcov", + "text", + "cobertura" + ], + "coverageDirectory": "/__tests__/__results__/unit/coverage" + }, + "jest-junit": { + "output": "__tests__/__results__/junit.xml" + }, + "jest-html-reporter": { + "pageTitle": "Zowe cics-deploy Plugin Test Results", + "outputPath": "__tests__/__results__/results.html", + "includeFailureMsg": true + }, + "author": "IBM Corp", + "contributors": [ + "Contributors to the Zowe Project" + ], + "license": "EPL-2.0" + } + \ No newline at end of file diff --git a/__tests__/__src__/TestUtils.ts b/__tests__/__src__/TestUtils.ts index 7415f8a7..4aae59ee 100644 --- a/__tests__/__src__/TestUtils.ts +++ b/__tests__/__src__/TestUtils.ts @@ -21,9 +21,9 @@ import {ITestEnvironment} from "./environment/doc/response/ITestEnvironment"; * @param testEnvironment - the test environment with env * @param [args=[]] - set of script args (optional) * @returns node.js details about the results of - * executing the script, including exit code and output + * executing the script, including exit code and output */ -export function runCliScript(scriptPath: string, testEnvironment: ITestEnvironment, args: any[] = []): SpawnSyncReturns { +export function runCliScript(scriptPath: string, testEnvironment: ITestEnvironment, args: any[] = []): SpawnSyncReturns { if (fs.existsSync(scriptPath)) { // We force the color off to prevent any oddities in the snapshots or expected values @@ -37,7 +37,8 @@ export function runCliScript(scriptPath: string, testEnvironment: ITestEnvironme fs.chmodSync(scriptPath, "755"); // Execute the command synchronously - return spawnSync(scriptPath, [].concat(args), {cwd: testEnvironment.workingDir, env: childEnv, shell: true, stdio: ["pipe", "pipe", "pipe"], windowsHide: true}); + return spawnSync(scriptPath, [].concat(args), {cwd: testEnvironment.workingDir, env: childEnv, shell: true, + stdio: ["pipe", "pipe", "pipe"], windowsHide: true}); } else { throw new Error(`The script file ${scriptPath} doesn't exist`); diff --git a/__tests__/__src__/environment/TestEnvironment.ts b/__tests__/__src__/environment/TestEnvironment.ts index e19f2e7c..4a6e5181 100644 --- a/__tests__/__src__/environment/TestEnvironment.ts +++ b/__tests__/__src__/environment/TestEnvironment.ts @@ -102,10 +102,10 @@ export class TestEnvironment { private static readonly DEFAULT_PROPERTIES_LOCATION = nodePath.resolve(__dirname + "/../../__resources__/properties/") + "/"; /** - * Load the properties file specified with system test configuration information. - * @param filePath - Specify the filePath of the properties file. Leave empty to use the properties - * file specified in the process.env (see gulp tasks for more information). - * @returns The parsed test properties. + * Load the properties file specified with system test configuration information. + * @param filePath - Specify the filePath of the properties file. Leave empty to use the properties + * file specified in the process.env (see gulp tasks for more information). + * @returns The parsed test properties. */ private static loadSystemTestProperties(filePath: string = null, workingDir: string = process.cwd()): ITestPropertiesSchema { diff --git a/__tests__/__system__/cli/generate/cli.generate.bundle.system.test.ts b/__tests__/__system__/cli/generate/cli.generate.bundle.system.test.ts index 3ad1101f..54d49e7a 100644 --- a/__tests__/__system__/cli/generate/cli.generate.bundle.system.test.ts +++ b/__tests__/__system__/cli/generate/cli.generate.bundle.system.test.ts @@ -86,7 +86,8 @@ describe("cics-deploy generate bundle", () => { }); it("should generate a bundle using values supplied when there's no package.json", async () => { - await testBundleGenerateWorks(["--bundleid", "mybundle", "--nodejsapp", "myapp", "--startscript", "server.js"], "myapp", NO_PACKAGE_JSON_APP); + await testBundleGenerateWorks(["--bundleid", "mybundle", "--nodejsapp", "myapp", "--startscript", "server.js"], + "myapp", NO_PACKAGE_JSON_APP); }); it("should return an error if invalid bundle version is supplied", async () => { diff --git a/__tests__/api/BundleContent/AutoBundler.test.ts b/__tests__/api/BundleContent/AutoBundler.test.ts index b4dd70d1..234593ef 100644 --- a/__tests__/api/BundleContent/AutoBundler.test.ts +++ b/__tests__/api/BundleContent/AutoBundler.test.ts @@ -123,9 +123,9 @@ describe("AutoBundler01", () => { let err: Error; try { - const ab = new AutoBundler("__tests__/__resources__/ExampleBundle01", parms); + const ab = new AutoBundler("__tests__/__resources__/ExampleBundle01", parms); } catch (e) { - err = e; + err = e; } expect(err).toBeDefined(); @@ -181,31 +181,31 @@ describe("AutoBundler01", () => { }); function setCommonParmsForAutoBundleTests(parms: IHandlerParameters) { - parms.arguments.merge = true; - parms.arguments.overwrite = true; - parms.arguments.port = undefined; - parms.arguments.nodejsapp = undefined; - parms.arguments.startscript = undefined; - parms.arguments.bundleid = undefined; - parms.arguments.bundleversion = undefined; + parms.arguments.merge = true; + parms.arguments.overwrite = true; + parms.arguments.port = undefined; + parms.arguments.nodejsapp = undefined; + parms.arguments.startscript = undefined; + parms.arguments.bundleid = undefined; + parms.arguments.bundleversion = undefined; } async function runAutoBundleWithError(parms: IHandlerParameters, dir: string) { - let err: Error; - try { - const ab = new AutoBundler(dir, parms); - } catch (e) { - err = e; - } + let err: Error; + try { + const ab = new AutoBundler(dir, parms); + } catch (e) { + err = e; + } - expect(err).toBeDefined(); - expect(err.message).toMatchSnapshot(); + expect(err).toBeDefined(); + expect(err.message).toMatchSnapshot(); } async function runAutoBundle(parms: IHandlerParameters, dir: string) { - const ab = new AutoBundler(dir, parms); + const ab = new AutoBundler(dir, parms); - expect(JSON.stringify(ab.getBundle().getManifest())).toMatchSnapshot(); + expect(JSON.stringify(ab.getBundle().getManifest())).toMatchSnapshot(); } diff --git a/__tests__/api/BundleContent/BundleMocked.test.ts b/__tests__/api/BundleContent/BundleMocked.test.ts index 60c4aa2f..a8e91d8c 100644 --- a/__tests__/api/BundleContent/BundleMocked.test.ts +++ b/__tests__/api/BundleContent/BundleMocked.test.ts @@ -17,19 +17,19 @@ import * as parser from "fast-xml-parser"; // work as the jest implementation will itself need to interact with the filesystem. describe("MockedFilesystemTests", () => { afterEach(() => { - jest.restoreAllMocks(); + jest.restoreAllMocks(); }); it("should tolerate META-INF directory not existing", () => { // Mocks for the manifest - META-INF exists jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { - if (path.endsWith("META-INF")) { - return false; - } - if (path.endsWith(".zosattributes")) { - return false; - } - return true; + if (path.endsWith("META-INF")) { + return false; + } + if (path.endsWith(".zosattributes")) { + return false; + } + return true; }); // Mocks for the manifest - Bundle dir writable @@ -37,11 +37,11 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeUndefined(); @@ -54,11 +54,11 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -73,11 +73,11 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -92,15 +92,16 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); - expect(err.message).toContain("A bundle manifest file already exists. Specify --overwrite to replace it, or --merge to merge changes into it."); + expect(err.message).toContain("A bundle manifest file already exists. Specify " + + "--overwrite to replace it, or --merge to merge changes into it."); }); it("should complain if no write permission to manifest", () => { @@ -108,19 +109,19 @@ describe("MockedFilesystemTests", () => { jest.spyOn(fs, "existsSync").mockReturnValue(true); // Mocks for the manifest - META-INF is writable, but manifest is not. jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { - if (path.endsWith("cics.xml")) { - throw new Error("Wibble"); - } - return true; + if (path.endsWith("cics.xml")) { + throw new Error("Wibble"); + } + return true; }); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -130,35 +131,36 @@ describe("MockedFilesystemTests", () => { it("should tolerate absence of .nodejsapp directory", () => { jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { - if (path.endsWith("nodejsapps")) { - return false; - } - if (path.endsWith(".nodejsapp")) { - return false; - } - if (path.endsWith("cics.xml")) { - return false; - } - if (path.endsWith(".profile")) { - return false; - } - if (path.endsWith(".zosattributes")) { - return false; - } - return true; + if (path.endsWith("nodejsapps")) { + return false; + } + if (path.endsWith(".nodejsapp")) { + return false; + } + if (path.endsWith("cics.xml")) { + return false; + } + if (path.endsWith(".profile")) { + return false; + } + if (path.endsWith(".zosattributes")) { + return false; + } + return true; }); // Mocks for the Nodejsapp - META-INF writable & nodejsapp dir creatable - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -167,16 +169,16 @@ describe("MockedFilesystemTests", () => { it("should detect inability to create .nodejsapp directory", () => { jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("nodejsapps")) { - return false; + return false; } if (path.endsWith("cics.xml")) { - return false; + return false; } if (path.endsWith(".zosattributes")) { return false; - } + } return true; - }); + }); // Bundle dir is unwriteable, so nodejsapps can't be created jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { @@ -188,13 +190,14 @@ describe("MockedFilesystemTests", () => { // Create a Bundle const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); + // eslint-disable-next-line no-magic-numbers bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); let err: Error; try { - bund.prepareForSave(); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -203,13 +206,13 @@ describe("MockedFilesystemTests", () => { it("should detect unwritable nodejsapps directory", () => { jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } if (path.endsWith(".zosattributes")) { return false; - } + } return true; - }); + }); jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { if (path.endsWith("nodejsapps")) { @@ -220,14 +223,15 @@ describe("MockedFilesystemTests", () => { // Create a Bundle const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); let err: Error; try { - bund.prepareForSave(); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -238,22 +242,23 @@ describe("MockedFilesystemTests", () => { // manifest don't exist, everying else does (inlucde .nodejsapp) jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } return true; - }); + }); // Mocks for the Nodejsapp - META-INF writable & nodejsapp dir creatable - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -263,10 +268,10 @@ describe("MockedFilesystemTests", () => { // manifest don't exist, everying else does (inlucde .nodejsapp) jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } return true; - }); + }); jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { if (path.endsWith(".nodejsapp")) { @@ -278,12 +283,13 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -294,10 +300,10 @@ describe("MockedFilesystemTests", () => { // manifest don't exist, everying else does jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } return true; - }); + }); jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { if (path.endsWith(".profile")) { @@ -308,12 +314,13 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -324,7 +331,7 @@ describe("MockedFilesystemTests", () => { jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } if (path.endsWith(".nodejsapp")) { return false; @@ -333,7 +340,7 @@ describe("MockedFilesystemTests", () => { return false; } return true; - }); + }); jest.spyOn(fs, "accessSync").mockImplementation((path: string) => { if (path.endsWith(".zosattributes")) { @@ -344,39 +351,40 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.prepareForSave(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, false); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); expect(err.message).toContain(".zosattributes already exists. Specify --overwrite to replace it."); }); it("should complain if can't make a new META-INF directory", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); - // manifest don't exist, everying else does + jest.spyOn(fs, "accessSync").mockReturnValue(); + // manifest don't exist, everying else does jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("META-INF")) { - return false; + return false; } return true; - }); + }); jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { - return true; + return true; }); jest.spyOn(fs, "mkdirSync").mockImplementationOnce(() => { throw new Error("InjectedError"); }); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -385,30 +393,30 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should complain if writing the manifest fails", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); - // manifest don't exist, everying else does + jest.spyOn(fs, "accessSync").mockReturnValue(); + // manifest don't exist, everying else does jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("cics.xml")) { - return false; + return false; } return true; - }); + }); // Mocks for the manifest - manifest write jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { - if (path.endsWith("cics.xml")) { - throw new Error("InjectedError"); - } + if (path.endsWith("cics.xml")) { + throw new Error("InjectedError"); + } }); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, true); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -417,27 +425,28 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should complain if creating nodejsapps dir fails", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith("nodejsapps")) { - return false; + return false; } return true; - }); + }); jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { - return true; + return true; }); jest.spyOn(fs, "mkdirSync").mockImplementationOnce(() => { throw new Error("InjectedError"); }); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -446,27 +455,28 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should complain if writing .nodejsapp file fails", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith(".nodejsapp")) { - return false; + return false; } return true; - }); + }); jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { - if (path.endsWith(".nodejsapp")) { - throw new Error("InjectedError"); - } + if (path.endsWith(".nodejsapp")) { + throw new Error("InjectedError"); + } }); let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -475,13 +485,13 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should complain if writing .profile fails", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith(".profile")) { return false; - } + } return true; - }); + }); jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { if (path.endsWith(".profile")) { @@ -491,12 +501,13 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -505,13 +516,13 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should complain if writing .zosattributes fails", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); jest.spyOn(fs, "existsSync").mockImplementation((path: string) => { if (path.endsWith(".zosattributes")) { return false; - } + } return true; - }); + }); // Mocks for the nodejsapp - write .zosattributes jest.spyOn(fs, "writeFileSync").mockImplementation((path: string) => { @@ -522,12 +533,13 @@ describe("MockedFilesystemTests", () => { let err: Error; try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); - bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); - bund.save(); + const bund = new Bundle("__tests__/__resources__/ExampleBundle03", false, true); + // eslint-disable-next-line no-magic-numbers + bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); + bund.save(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -536,19 +548,19 @@ describe("MockedFilesystemTests", () => { expect(err.message).toContain("InjectedError"); }); it("should know if the bundle is valid", () => { - jest.spyOn(fs, "accessSync").mockReturnValue(true); + jest.spyOn(fs, "accessSync").mockReturnValue(); jest.spyOn(fs, "existsSync").mockReturnValue(false); - jest.spyOn(fs, "writeFileSync").mockReturnValue(true); - jest.spyOn(fs, "mkdirSync").mockReturnValue(true); + jest.spyOn(fs, "writeFileSync").mockReturnValue(); + jest.spyOn(fs, "mkdirSync").mockReturnValue(); let err: Error; let bund; try { - bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); - bund.validate(); + bund = new Bundle("__tests__/__resources__/ExampleBundle01", false, false); + bund.validate(); } catch (error) { - err = error; + err = error; } expect(err).toBeDefined(); @@ -557,11 +569,11 @@ describe("MockedFilesystemTests", () => { err = undefined; try { - bund.save(); - bund.validate(); + bund.save(); + bund.validate(); } catch (error) { - err = error; + err = error; } expect(err).toBeUndefined(); @@ -569,17 +581,17 @@ describe("MockedFilesystemTests", () => { it("should complain if exceptions are thrown during manifest parsing", () => { - jest.spyOn(parser, "parse").mockImplementationOnce(() => { throw new Error("Wibble"); }); + jest.spyOn(parser, "parse").mockImplementationOnce(() => { throw new Error("Wibble"); }); - let err: Error; - try { - const bund = new Bundle("__tests__/__resources__/ExampleBundle01", true, true); - } - catch (error) { - err = error; - } + let err: Error; + try { + const bund = new Bundle("__tests__/__resources__/ExampleBundle01", true, true); + } + catch (error) { + err = error; + } - expect(err).toBeDefined(); - expect(err.message).toContain("Parsing error occurred reading a CICS manifest file: Wibble"); + expect(err).toBeDefined(); + expect(err.message).toContain("Parsing error occurred reading a CICS manifest file: Wibble"); }); }); diff --git a/__tests__/api/BundleContent/BundleSimple.test.ts b/__tests__/api/BundleContent/BundleSimple.test.ts index 17f7b85f..4be8d5ab 100644 --- a/__tests__/api/BundleContent/BundleSimple.test.ts +++ b/__tests__/api/BundleContent/BundleSimple.test.ts @@ -14,7 +14,7 @@ import * as fs from "fs"; describe("Bundle01", () => { afterEach(() => { - jest.restoreAllMocks(); + jest.restoreAllMocks(); }); it("should read an existing bundle", () => { @@ -34,6 +34,7 @@ describe("Bundle01", () => { expect(bund.getId()).toMatch("TestExample"); // Set the Version + // eslint-disable-next-line no-magic-numbers bund.setVersion(33, 44, 55); // Check the output as JSON @@ -60,10 +61,10 @@ describe("Bundle01", () => { // Add a definition that's out of scope let err: Error; try { - bund.addDefinition({name: "name1", type: "type1", path: "__tests__/__resources__/ExampleBundle01/META-INF/cics.xml"}); + bund.addDefinition({name: "name1", type: "type1", path: "__tests__/__resources__/ExampleBundle01/META-INF/cics.xml"}); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -79,10 +80,10 @@ describe("Bundle01", () => { // Add a definition let err: Error; try { - bund.addDefinition({name: "name1", type: "type1", path: "__tests__/__resources__/ExampleBundle02/Artefact3"}); + bund.addDefinition({name: "name1", type: "type1", path: "__tests__/__resources__/ExampleBundle02/Artefact3"}); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -98,10 +99,10 @@ describe("Bundle01", () => { // Add a definition let err: Error; try { - bund.addDefinition({name: undefined, type: "type1", path: "__tests__/__resources__/ExampleBundle02/Artefact1"}); + bund.addDefinition({name: undefined, type: "type1", path: "__tests__/__resources__/ExampleBundle02/Artefact1"}); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -115,10 +116,10 @@ describe("Bundle01", () => { // Add a definition let err: Error; try { - bund.addDefinition({name: "name1", type: undefined, path: "__tests__/__resources__/ExampleBundle02/Artefact1"}); + bund.addDefinition({name: "name1", type: undefined, path: "__tests__/__resources__/ExampleBundle02/Artefact1"}); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -132,10 +133,10 @@ describe("Bundle01", () => { // Add a definition let err: Error; try { - bund.addDefinition({name: "name1", type: "type1", path: undefined}); + bund.addDefinition({name: "name1", type: "type1", path: undefined}); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -169,6 +170,7 @@ describe("Bundle01", () => { const bund = new Bundle("__tests__/__resources__/ExampleBundle03", true, true); // Add a definition + // eslint-disable-next-line no-magic-numbers bund.addNodejsappDefinition("NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000); // Check the manifest as JSON @@ -183,10 +185,10 @@ describe("Bundle01", () => { let err: Error; try { - bund.prepareForSave(); + bund.prepareForSave(); } catch (error) { - err = error; + err = error; } // Check the output as JSON diff --git a/__tests__/api/BundleContent/Manifest.test.ts b/__tests__/api/BundleContent/Manifest.test.ts index 2c075913..a2062e25 100644 --- a/__tests__/api/BundleContent/Manifest.test.ts +++ b/__tests__/api/BundleContent/Manifest.test.ts @@ -69,10 +69,10 @@ describe("Manifest01", () => { // Add a definition let err: Error; try { - man.setBundleId(undefined); + man.setBundleId(undefined); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -84,6 +84,7 @@ describe("Manifest01", () => { const man = new Manifest("__tests__/__resources__/ExampleBundle01", true, true); // Set a bundleId + // eslint-disable-next-line no-magic-numbers man.setBundleVersion(1, 2, 3); // Check the output as JSON @@ -96,11 +97,11 @@ describe("Manifest01", () => { let err: Error; try { - // Set a bundleId - man.setBundleVersion(-1, 0, 0); + // Set a bundleId + man.setBundleVersion(-1, 0, 0); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -113,11 +114,12 @@ describe("Manifest01", () => { let err: Error; try { - // Set a bundleId - man.setBundleVersion(1, 3.4, 0); + // Set a bundleId + // eslint-disable-next-line no-magic-numbers + man.setBundleVersion(1, 3.4, 0); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -130,11 +132,12 @@ describe("Manifest01", () => { let err: Error; try { - // Set a bundleId - man.setBundleVersion(1, 3, 4.3); + // Set a bundleId + // eslint-disable-next-line no-magic-numbers + man.setBundleVersion(1, 3, 4.3); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -147,11 +150,11 @@ describe("Manifest01", () => { let err: Error; try { - // Set a bundleId - man.setBundleVersion(undefined, undefined, undefined); + // Set a bundleId + man.setBundleVersion(undefined, undefined, undefined); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -162,10 +165,10 @@ describe("Manifest01", () => { // Read a bad manifest let err: Error; try { - const man = new Manifest("__tests__/__resources__/BadManifestBundle01", true, true); + const man = new Manifest("__tests__/__resources__/BadManifestBundle01", true, true); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -176,10 +179,10 @@ describe("Manifest01", () => { // Read a bad manifest let err: Error; try { - const man = new Manifest("__tests__/__resources__/BadManifestBundle02", true, true); + const man = new Manifest("__tests__/__resources__/BadManifestBundle02", true, true); } catch (error) { - err = error; + err = error; } // Check the output as JSON diff --git a/__tests__/api/BundleContent/Nodejsapp.test.ts b/__tests__/api/BundleContent/Nodejsapp.test.ts index 983316d8..0a1e6472 100644 --- a/__tests__/api/BundleContent/Nodejsapp.test.ts +++ b/__tests__/api/BundleContent/Nodejsapp.test.ts @@ -14,7 +14,9 @@ describe("NodejsappBundlePart01", () => { it("Create a NodejsappBundlePart", () => { // Create a Nodejsapp - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName", + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); expect(JSON.stringify(njs.getPart())).toMatchSnapshot(); expect(njs.getPartXML()).toMatchSnapshot(); @@ -24,7 +26,9 @@ describe("NodejsappBundlePart01", () => { it("Create a NodejsappBundlePart with bad chars", () => { // Create a Nodejsapp - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName is invalid!!!", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName is invalid!!!", + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); expect(JSON.stringify(njs.getPart())).toMatchSnapshot(); expect(njs.getPartXML()).toMatchSnapshot(); @@ -34,7 +38,9 @@ describe("NodejsappBundlePart01", () => { it("Create a NodejsappBundlePart with long name", () => { // Create a Nodejsapp - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "123456789012345678901234567890123", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "123456789012345678901234567890123", + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); expect(JSON.stringify(njs.getPart())).toMatchSnapshot(); expect(njs.getPartXML()).toMatchSnapshot(); @@ -45,10 +51,11 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", undefined, "", 1000, false); + // eslint-disable-next-line no-magic-numbers + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", undefined, "", 1000, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -58,10 +65,12 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", "__tests__/__resources__/ExampleBundle03/Artefact2", 1000, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact2", 1000, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -71,10 +80,11 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", undefined, 1000, false); + // eslint-disable-next-line no-magic-numbers + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", undefined, 1000, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -84,10 +94,11 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", "__tests__/__resources__/ExampleBundle03/Artefact1", -1, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", + "__tests__/__resources__/ExampleBundle03/Artefact1", -1, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON @@ -97,19 +108,23 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", "__tests__/__resources__/ExampleBundle03/Artefact1", 1000.1, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "test", + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact1", 1000.1, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON + // eslint-disable-next-line no-magic-numbers expect(err.message).toContain("Supplied Port is not an integer: 1000.1"); }); it("Create a NodejsappBundlePart with missing port number", () => { // Create a Nodejsapp - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName", "__tests__/__resources__/ExampleBundle03/Artefact1", undefined, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", "NodeName", + "__tests__/__resources__/ExampleBundle03/Artefact1", undefined, false); // Check the bundle part as JSON expect(JSON.stringify(njs.getPart())).toMatchSnapshot(); @@ -121,10 +136,12 @@ describe("NodejsappBundlePart01", () => { let err: Error; try { - const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", undefined, "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); + const njs = new NodejsappBundlePart("__tests__/__resources__/ExampleBundle03", undefined, + // eslint-disable-next-line no-magic-numbers + "__tests__/__resources__/ExampleBundle03/Artefact1", 1000, false); } catch (error) { - err = error; + err = error; } // Check the output as JSON diff --git a/__tests__/api/BundleContent/__snapshots__/AutoBundler.test.ts.snap b/__tests__/api/BundleContent/__snapshots__/AutoBundler.test.ts.snap index 35fe8d10..e9df2952 100644 --- a/__tests__/api/BundleContent/__snapshots__/AutoBundler.test.ts.snap +++ b/__tests__/api/BundleContent/__snapshots__/AutoBundler.test.ts.snap @@ -1,29 +1,33 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`AutoBundler01 should cope with an empty directory 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":1,\\"bundleRelease\\":0}}"`; +exports[`AutoBundler01 should cope with an empty directory 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":1,"bundleRelease":0}}"`; -exports[`AutoBundler01 should cope with an empty directory and generate a NODEJSAPP 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":1,\\"bundleRelease\\":0,\\"define\\":[{\\"name\\":\\"wibble\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/wibble.nodejsapp\\"}]}}"`; +exports[`AutoBundler01 should cope with an empty directory and generate a NODEJSAPP 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":1,"bundleRelease":0,"define":[{"name":"wibble","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/wibble.nodejsapp"}]}}"`; exports[`AutoBundler01 should detect --merge without --overwrite 1`] = `"--merge requires the use of --overwrite"`; -exports[`AutoBundler01 should detect a bad package.json 1`] = `"Parsing error occurred reading package.json: Unexpected token g in JSON at position 0"`; +exports[`AutoBundler01 should detect a bad package.json 1`] = ` +"Parsing error occurred reading package.json: Unexpected token 'g', "garbage -exports[`AutoBundler01 should not merge an existing bundle 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":1,\\"bundleRelease\\":0}}"`; +" is not valid JSON" +`; -exports[`AutoBundler01 should read an existing bundle 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`AutoBundler01 should not merge an existing bundle 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":1,"bundleRelease":0}}"`; -exports[`AutoBundler01 should receive default values from package.json 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"id\\":\\"testBundleName\\",\\"bundleMajorVer\\":1,\\"bundleMinorVer\\":0,\\"bundleMicroVer\\":0,\\"define\\":[{\\"name\\":\\"testBundleName\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/testBundleName.nodejsapp\\"}]}}"`; +exports[`AutoBundler01 should read an existing bundle 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; -exports[`AutoBundler01 should set a nodejsapp name 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"id\\":\\"testBundleName\\",\\"bundleMajorVer\\":1,\\"bundleMinorVer\\":0,\\"bundleMicroVer\\":0,\\"define\\":[{\\"name\\":\\"MyExampleOverride\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/MyExampleOverride.nodejsapp\\"}]}}"`; +exports[`AutoBundler01 should receive default values from package.json 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","id":"testBundleName","bundleMajorVer":1,"bundleMinorVer":0,"bundleMicroVer":0,"define":[{"name":"testBundleName","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/testBundleName.nodejsapp"}]}}"`; + +exports[`AutoBundler01 should set a nodejsapp name 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","id":"testBundleName","bundleMajorVer":1,"bundleMinorVer":0,"bundleMicroVer":0,"define":[{"name":"MyExampleOverride","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/MyExampleOverride.nodejsapp"}]}}"`; exports[`AutoBundler01 should set a port number 1`] = `"Supplied Port is outside the range of 1-65535: -27"`; -exports[`AutoBundler01 should set the bundle version 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleMajorVer\\":3,\\"bundleMinorVer\\":4,\\"bundleMicroVer\\":5}}"`; +exports[`AutoBundler01 should set the bundle version 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleMajorVer":3,"bundleMinorVer":4,"bundleMicroVer":5}}"`; -exports[`AutoBundler01 should set the bundleid 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"id\\":\\"test\\"}}"`; +exports[`AutoBundler01 should set the bundleid 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","id":"test"}}"`; -exports[`AutoBundler01 should support main script from package.json 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"id\\":\\"testBundleName\\",\\"bundleMajorVer\\":1,\\"bundleMinorVer\\":0,\\"bundleMicroVer\\":0,\\"define\\":[{\\"name\\":\\"testBundleName\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/testBundleName.nodejsapp\\"}]}}"`; +exports[`AutoBundler01 should support main script from package.json 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","id":"testBundleName","bundleMajorVer":1,"bundleMinorVer":0,"bundleMicroVer":0,"define":[{"name":"testBundleName","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/testBundleName.nodejsapp"}]}}"`; -exports[`AutoBundler01 should tolerate an almost empty package.json 1`] = `"No startscript value set for NODEJSAPP \\"almostEmpty\\""`; +exports[`AutoBundler01 should tolerate an almost empty package.json 1`] = `"No startscript value set for NODEJSAPP "almostEmpty""`; exports[`AutoBundler01 should tolerate an empty package.json 1`] = `"No bundleid value set"`; diff --git a/__tests__/api/BundleContent/__snapshots__/BundleSimple.test.ts.snap b/__tests__/api/BundleContent/__snapshots__/BundleSimple.test.ts.snap index 81888120..7214594f 100644 --- a/__tests__/api/BundleContent/__snapshots__/BundleSimple.test.ts.snap +++ b/__tests__/api/BundleContent/__snapshots__/BundleSimple.test.ts.snap @@ -1,28 +1,28 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Bundle01 add a NODEJSAPP 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"define\\":[{\\"name\\":\\"NodeName\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/NodeName.nodejsapp\\"}]}}"`; +exports[`Bundle01 add a NODEJSAPP 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","define":[{"name":"NodeName","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/NodeName.nodejsapp"}]}}"`; exports[`Bundle01 add a NODEJSAPP 2`] = ` -" +" " `; exports[`Bundle01 add a part with missing name 1`] = `"BundlePart name is not set."`; -exports[`Bundle01 add a part with missing path 1`] = `"BundlePart path is not set for part \\"name1\\""`; +exports[`Bundle01 add a part with missing path 1`] = `"BundlePart path is not set for part "name1""`; -exports[`Bundle01 add a part with missing type 1`] = `"BundlePart type is not set for part \\"name1\\""`; +exports[`Bundle01 add a part with missing type 1`] = `"BundlePart type is not set for part "name1""`; -exports[`Bundle01 add definitions 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"Artefact1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"Artefact2.txt\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"type3\\",\\"path\\":\\"folder/Artefact3.jpg\\"}]}}"`; +exports[`Bundle01 add definitions 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"Artefact1"},{"name":"name2","type":"type2","path":"Artefact2.txt"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"},{"name":"name3","type":"type3","path":"folder/Artefact3.jpg"}]}}"`; -exports[`Bundle01 set the id and version 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"TestExample\\",\\"bundleMajorVer\\":33,\\"bundleMinorVer\\":44,\\"bundleMicroVer\\":55,\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Bundle01 set the id and version 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"TestExample","bundleMajorVer":33,"bundleMinorVer":44,"bundleMicroVer":55,"define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; -exports[`Bundle01 should be able to add a resource to a single item manifest 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"define\\":[{\\"name\\":\\"single\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"item2\\",\\"type\\":\\"type2\\",\\"path\\":\\"Artefact1\\"}]}}"`; +exports[`Bundle01 should be able to add a resource to a single item manifest 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","define":[{"name":"single","type":"type1","path":"path1"},{"name":"item2","type":"type2","path":"Artefact1"}]}}"`; -exports[`Bundle01 should be able to save new definitions 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"Artefact1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Bundle01 should be able to save new definitions 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"Artefact1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; -exports[`Bundle01 should read an existing bundle 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Bundle01 should read an existing bundle 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; exports[`Bundle01 should warn that an existing bundle cant be overwritten 1`] = `"A bundle manifest file already exists. Specify --overwrite to replace it, or --merge to merge changes into it."`; -exports[`Bundle01 tolerate an existing almost empty manifest 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"Artefact1\\"}]}}"`; +exports[`Bundle01 tolerate an existing almost empty manifest 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","define":[{"name":"name1","type":"type1","path":"Artefact1"}]}}"`; diff --git a/__tests__/api/BundleContent/__snapshots__/Manifest.test.ts.snap b/__tests__/api/BundleContent/__snapshots__/Manifest.test.ts.snap index 09925ba9..952ba119 100644 --- a/__tests__/api/BundleContent/__snapshots__/Manifest.test.ts.snap +++ b/__tests__/api/BundleContent/__snapshots__/Manifest.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Manifest01 set a long bundleId 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"1234567890123456789012345678901234567890123456789012345678901234\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Manifest01 set a long bundleId 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"1234567890123456789012345678901234567890123456789012345678901234","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; exports[`Manifest01 set a long bundleId 2`] = `"1234567890123456789012345678901234567890123456789012345678901234"`; @@ -8,7 +8,7 @@ exports[`Manifest01 set a null bundleId 1`] = `"BundleId not set."`; exports[`Manifest01 set a null version number 1`] = `"Invalid Bundle major version specified: undefined."`; -exports[`Manifest01 set a valid version number 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":1,\\"bundleMinorVer\\":2,\\"bundleMicroVer\\":3,\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Manifest01 set a valid version number 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":1,"bundleMinorVer":2,"bundleMicroVer":3,"define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; exports[`Manifest01 set an invalid major version number 1`] = `"Invalid Bundle major version specified: -1."`; @@ -16,17 +16,17 @@ exports[`Manifest01 set an invalid micro version number 1`] = `"Invalid Bundle m exports[`Manifest01 set an invalid minor version number 1`] = `"Invalid Bundle minor version specified: 3.4."`; -exports[`Manifest01 set the bundleId 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"testingXaXBundleId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Manifest01 set the bundleId 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"testingXaXBundleId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; exports[`Manifest01 set the bundleId 2`] = `"testingXaXBundleId"`; -exports[`Manifest01 should create an empty manifest from empty META-INF dir 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":1,\\"bundleRelease\\":0}}"`; +exports[`Manifest01 should create an empty manifest from empty META-INF dir 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":1,"bundleRelease":0}}"`; -exports[`Manifest01 should create an empty manifest from empty dir 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":1,\\"bundleRelease\\":0}}"`; +exports[`Manifest01 should create an empty manifest from empty dir 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":1,"bundleRelease":0}}"`; -exports[`Manifest01 should read an existing manifest 1`] = `"{\\"manifest\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle\\",\\"bundleVersion\\":\\"1\\",\\"bundleRelease\\":\\"2\\",\\"id\\":\\"ThisIsAnId\\",\\"bundleMajorVer\\":\\"10\\",\\"bundleMinorVer\\":\\"11\\",\\"bundleMicroVer\\":\\"12\\",\\"define\\":[{\\"name\\":\\"name1\\",\\"type\\":\\"type1\\",\\"path\\":\\"path1\\"},{\\"name\\":\\"name2\\",\\"type\\":\\"type2\\",\\"path\\":\\"path2\\"},{\\"name\\":\\"name3\\",\\"type\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"path\\":\\"nodejsapps/Test.nodejsapp\\"}]}}"`; +exports[`Manifest01 should read an existing manifest 1`] = `"{"manifest":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle","bundleVersion":"1","bundleRelease":"2","id":"ThisIsAnId","bundleMajorVer":"10","bundleMinorVer":"11","bundleMicroVer":"12","define":[{"name":"name1","type":"type1","path":"path1"},{"name":"name2","type":"type2","path":"path2"},{"name":"name3","type":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","path":"nodejsapps/Test.nodejsapp"}]}}"`; exports[`Manifest01 should read an existing manifest 2`] = ` -" +" " `; diff --git a/__tests__/api/BundleContent/__snapshots__/Nodejsapp.test.ts.snap b/__tests__/api/BundleContent/__snapshots__/Nodejsapp.test.ts.snap index ae2b8c5a..cfa31efa 100644 --- a/__tests__/api/BundleContent/__snapshots__/Nodejsapp.test.ts.snap +++ b/__tests__/api/BundleContent/__snapshots__/Nodejsapp.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`NodejsappBundlePart01 Create a NodejsappBundlePart 1`] = `"{\\"nodejsapp\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"name\\":\\"NodeName\\",\\"startscript\\":\\"Artefact1\\",\\"profile\\":\\"nodejsapps/NodeName.profile\\",\\"lerunopts\\":\\"DFHSJNRO\\"}}"`; +exports[`NodejsappBundlePart01 Create a NodejsappBundlePart 1`] = `"{"nodejsapp":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","name":"NodeName","startscript":"Artefact1","profile":"nodejsapps/NodeName.profile","lerunopts":"DFHSJNRO"}}"`; exports[`NodejsappBundlePart01 Create a NodejsappBundlePart 2`] = ` -" +" " `; @@ -16,9 +16,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart 3`] = ` # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -146,9 +146,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart 4`] = ` # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -267,10 +267,10 @@ PORT=1000 " `; -exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with bad chars 1`] = `"{\\"nodejsapp\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"name\\":\\"NodeNameXisXinvalidXXX\\",\\"startscript\\":\\"Artefact1\\",\\"profile\\":\\"nodejsapps/NodeNameXisXinvalidXXX.profile\\",\\"lerunopts\\":\\"DFHSJNRO\\"}}"`; +exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with bad chars 1`] = `"{"nodejsapp":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","name":"NodeNameXisXinvalidXXX","startscript":"Artefact1","profile":"nodejsapps/NodeNameXisXinvalidXXX.profile","lerunopts":"DFHSJNRO"}}"`; exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with bad chars 2`] = ` -" +" " `; @@ -283,9 +283,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with bad chars 3`] = # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -413,9 +413,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with bad chars 4`] = # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -534,10 +534,10 @@ PORT=1000 " `; -exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with long name 1`] = `"{\\"nodejsapp\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"name\\":\\"12345678901234567890123456789012\\",\\"startscript\\":\\"Artefact1\\",\\"profile\\":\\"nodejsapps/12345678901234567890123456789012.profile\\",\\"lerunopts\\":\\"DFHSJNRO\\"}}"`; +exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with long name 1`] = `"{"nodejsapp":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","name":"12345678901234567890123456789012","startscript":"Artefact1","profile":"nodejsapps/12345678901234567890123456789012.profile","lerunopts":"DFHSJNRO"}}"`; exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with long name 2`] = ` -" +" " `; @@ -550,9 +550,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with long name 3`] = # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -680,9 +680,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with long name 4`] = # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -801,10 +801,10 @@ PORT=1000 " `; -exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with missing port number 1`] = `"{\\"nodejsapp\\":{\\"xmlns\\":\\"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP\\",\\"name\\":\\"NodeName\\",\\"startscript\\":\\"Artefact1\\",\\"profile\\":\\"nodejsapps/NodeName.profile\\",\\"lerunopts\\":\\"DFHSJNRO\\"}}"`; +exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with missing port number 1`] = `"{"nodejsapp":{"xmlns":"http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP","name":"NodeName","startscript":"Artefact1","profile":"nodejsapps/NodeName.profile","lerunopts":"DFHSJNRO"}}"`; exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with missing port number 2`] = ` -" +" " `; @@ -817,9 +817,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with missing port nu # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # @@ -946,9 +946,9 @@ exports[`NodejsappBundlePart01 Create a NodejsappBundlePart with missing port nu # and to set environment variables for use by the application. # # # # Lines starting with # are treated as comments and ignored. # -# Lines ending with \\\\ are continued on the next line. # +# Lines ending with \\ are continued on the next line. # # # -# See topic \\"Node.js profile validation and properties\\" # +# See topic "Node.js profile validation and properties" # # in the Knowledge Center: # # http://www.ibm.com/support/knowledgecenter/SSGMCP_5.5.0 # # # diff --git a/__tests__/api/BundleDeploy/BundleDeployer.test.ts b/__tests__/api/BundleDeploy/BundleDeployer.test.ts index b83f4ac0..1a609963 100644 --- a/__tests__/api/BundleDeploy/BundleDeployer.test.ts +++ b/__tests__/api/BundleDeploy/BundleDeployer.test.ts @@ -24,7 +24,7 @@ const DEFAULT_PARAMTERS: IHandlerParameters = { profiles: { get: (type: string) => { if (profileError === true) { - throw new Error("Profile Error"); + throw new Error("Profile Error"); } return { host: "testname", user: "testuser", password: "testpwd" }; } @@ -58,16 +58,19 @@ const DEFAULT_PARAMTERS: IHandlerParameters = { }; -let createSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({})); -let listSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ({})); -let submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => ({})); -let profileError = false; +let createSpy : jest.SpyInstance; +let listSpy : jest.SpyInstance; +let submitSpy : jest.SpyInstance; +let profileError : boolean; describe("BundleDeployer01", () => { beforeEach(() => { + // @ts-ignore createSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({})); + // @ts-ignore listSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ( { val: "DFHDPLOY EYU9ABSI" })); + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => ({})); profileError = false; }); @@ -110,16 +113,20 @@ describe("BundleDeployer01", () => { expect(listSpy).toHaveBeenCalledTimes(1); }); it("should complain if cpsmhlq not found", async () => { + // listSpy = jest.spyOn(List, "allMembers").mockImplementationOnce(() => ( { val1: "DFHDPLOY"})) + // @ts-ignore listSpy = jest.spyOn(List, "allMembers").mockImplementationOnce(() => ( { val1: "DFHDPLOY"})) - .mockImplementationOnce(() => { throw new Error( "Injected CPSMHLQ error" ); }); + .mockImplementationOnce(() => { throw new Error( "Injected CPSMHLQ error" ); }); await runDeployTestWithError(); expect(createSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(2); }); it("should complain if cpsmhlq not found2", async () => { + // @ts-ignore listSpy = jest.spyOn(List, "allMembers").mockImplementationOnce(() => ( { val: "DFHDPLOY" })) - .mockImplementationOnce(() => ( { val: "wibble" })); + // @ts-ignore + .mockImplementationOnce(() => ( { val: "wibble" })); await runDeployTestWithError(); expect(createSpy).toHaveBeenCalledTimes(1); @@ -135,21 +142,23 @@ describe("BundleDeployer01", () => { }); it("should update the progress bar", async () => { submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementationOnce((session: any, jcl: string, parms: any) => { - parms.task.statusMessage = "Waiting for JOB12345 to enter OUTPUT"; - parms.task.stageName = TaskStage.IN_PROGRESS; - const expectedMsg = "Running DFHDPLOY (DEPLOY), jobid JOB12345"; - // wait 1.5 seconds - return new Promise((resolve, reject) => { - setTimeout(() => { + parms.task.statusMessage = "Waiting for JOB12345 to enter OUTPUT"; + parms.task.stageName = TaskStage.IN_PROGRESS; + const expectedMsg = "Running DFHDPLOY (DEPLOY), jobid JOB12345"; + // wait 1.5 seconds + return new Promise((resolve, reject) => { + setTimeout(() => { // Now check that the status message has been updated by the progress bar processing if (parms.task.statusMessage !== expectedMsg) { - throw new Error("Failed to find the expected message. Got: '" + parms.task.statusMessage + "' expected '" + + throw new Error("Failed to find the expected message. Got: '" + parms.task.statusMessage + "' expected '" + expectedMsg + "'"); } + // @ts-ignore resolve(); - }, 1500); - }); - }); + // eslint-disable-next-line no-magic-numbers + }, 1500); + }); + }); await runDeployTestWithError(); expect(createSpy).toHaveBeenCalledTimes(1); @@ -158,15 +167,16 @@ describe("BundleDeployer01", () => { }); it("should include the JOBID in an error", async () => { submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementationOnce((session: any, jcl: string, parms: any) => { - parms.task.statusMessage = "Waiting for JOB12345 to enter OUTPUT"; - parms.task.stageName = TaskStage.IN_PROGRESS; - // wait 1.5 seconds - return new Promise((resolve, reject) => { - setTimeout(() => { + parms.task.statusMessage = "Waiting for JOB12345 to enter OUTPUT"; + parms.task.stageName = TaskStage.IN_PROGRESS; + // wait 1.5 seconds + return new Promise((resolve, reject) => { + setTimeout(() => { reject(new Error("Injected submit error")); - }, 1500); - }); - }); + // eslint-disable-next-line no-magic-numbers + }, 1500); + }); + }); await runDeployTestWithError(); expect(createSpy).toHaveBeenCalledTimes(1); @@ -243,6 +253,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL with neither csdgroup nor resgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); await testDeployJCL(parms); @@ -250,6 +261,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for csdgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.csdgroup = "12345678"; @@ -258,6 +270,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for csdgroup with timeout", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.csdgroup = "12345678"; @@ -267,6 +280,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for resgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -275,6 +289,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for resgroup with timeout", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -284,6 +299,7 @@ describe("BundleDeployer01", () => { it("should support multi-line jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -294,6 +310,7 @@ describe("BundleDeployer01", () => { it("should support multi-line jobcard with embedded new lines", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -303,6 +320,7 @@ describe("BundleDeployer01", () => { it("should support long line jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -312,6 +330,7 @@ describe("BundleDeployer01", () => { it("should support really long line jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -323,6 +342,7 @@ describe("BundleDeployer01", () => { it("should fail with overlong jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -331,9 +351,9 @@ describe("BundleDeployer01", () => { "73CHARS=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1"; let err: Error; try { - await testDeployJCL(parms); + await testDeployJCL(parms); } catch (e) { - err = e; + err = e; } expect(err).toBeDefined(); expect(err.message).toMatchSnapshot(); @@ -341,6 +361,7 @@ describe("BundleDeployer01", () => { it("tolerate embedded quote", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -350,6 +371,7 @@ describe("BundleDeployer01", () => { it("tolerate embedded single quote", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -359,6 +381,7 @@ describe("BundleDeployer01", () => { it("tolerate quotes around jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -368,6 +391,7 @@ describe("BundleDeployer01", () => { it("tolerate single quotes around jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -377,6 +401,7 @@ describe("BundleDeployer01", () => { it("tolerate quotes around jobcard with embedded quote", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -386,6 +411,7 @@ describe("BundleDeployer01", () => { it("tolerate single quotes around jobcard with embedded single quote", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -395,6 +421,7 @@ describe("BundleDeployer01", () => { it("should tolerate a single leading slash for jobcard", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.jobcard = "/DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"; @@ -402,6 +429,7 @@ describe("BundleDeployer01", () => { }); it("should support long bundledir", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -414,6 +442,7 @@ describe("BundleDeployer01", () => { }); it("should tolerate bundledir with extra slasshes", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.bundledir = "//bundledir/with/extra//slashes"; @@ -422,6 +451,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for AVAILABLE", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "AVAILABLE"; @@ -431,6 +461,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for ENABLED", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "ENABLED"; @@ -440,6 +471,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for DISABLED", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "DISABLED"; @@ -449,6 +481,7 @@ describe("BundleDeployer01", () => { it("should generate deploy JCL for mixed case", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "disabled"; @@ -458,6 +491,7 @@ describe("BundleDeployer01", () => { it("should support verbose=true output for deploy", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "disabled"; @@ -468,6 +502,7 @@ describe("BundleDeployer01", () => { it("should support verbose=false output for deploy", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.targetstate = "disabled"; @@ -477,6 +512,7 @@ describe("BundleDeployer01", () => { }); it("should support long description", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.description = "1234567890123456789012345678901234567890123456789012345678"; @@ -487,6 +523,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL with neither csdgroup nor resgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); await testUndeployJCL(parms); @@ -494,6 +531,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for csdgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.csdgroup = "12345678"; @@ -502,6 +540,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for csdgroup with timeout", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.csdgroup = "12345678"; @@ -511,6 +550,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for resgroup", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -519,6 +559,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for resgroup with timeout", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.resgroup = "12345678"; @@ -528,6 +569,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for UNAVAILABLE", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "UNAVAILABLE"; @@ -537,6 +579,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for DISABLED", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "DISABLED"; @@ -546,6 +589,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for DISCARDED", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "DISCARDED"; @@ -555,6 +599,7 @@ describe("BundleDeployer01", () => { it("should generate undeploy JCL for mixed case", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "discarded"; @@ -564,6 +609,7 @@ describe("BundleDeployer01", () => { it("should support verbose=true output for undeploy", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "disabled"; @@ -574,6 +620,7 @@ describe("BundleDeployer01", () => { it("should support verbose=false output for undeploy", async () => { let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForUndeployTests(parms); parms.arguments.targetstate = "disabled"; @@ -586,6 +633,7 @@ describe("BundleDeployer01", () => { submitSpy.mockImplementationOnce(() => [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const parms = DEFAULT_PARAMTERS; setCommonParmsForDeployTests(parms); parms.arguments.csdgroup = "12345678"; @@ -602,105 +650,109 @@ describe("BundleDeployer01", () => { }); async function runDeployTestWithError() { - let parms: IHandlerParameters; - parms = DEFAULT_PARAMTERS; - setCommonParmsForDeployTests(parms); - parms.arguments.csdgroup = "12345678"; - - const bd = new BundleDeployer(parms); - - let err: Error; - try { - const response = await bd.deployBundle(); - } catch (e) { - err = e; - } - expect(err).toBeDefined(); - expect(err.message).toMatchSnapshot(); + let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const + parms = DEFAULT_PARAMTERS; + setCommonParmsForDeployTests(parms); + parms.arguments.csdgroup = "12345678"; + + const bd = new BundleDeployer(parms); + + let err: Error; + try { + const response = await bd.deployBundle(); + } catch (e) { + err = e; + } + expect(err).toBeDefined(); + expect(err.message).toMatchSnapshot(); } async function runUndeployTestWithError() { - let parms: IHandlerParameters; - parms = DEFAULT_PARAMTERS; - setCommonParmsForUndeployTests(parms); - parms.arguments.csdgroup = "12345678"; - - const bd = new BundleDeployer(parms); - - let err: Error; - try { - const response = await bd.undeployBundle(); - } catch (e) { - err = e; - } - expect(err).toBeDefined(); - expect(err.message).toMatchSnapshot(); + let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const + parms = DEFAULT_PARAMTERS; + setCommonParmsForUndeployTests(parms); + parms.arguments.csdgroup = "12345678"; + + const bd = new BundleDeployer(parms); + + let err: Error; + try { + const response = await bd.undeployBundle(); + } catch (e) { + err = e; + } + expect(err).toBeDefined(); + expect(err.message).toMatchSnapshot(); } async function runDeployTest() { - let parms: IHandlerParameters; - parms = DEFAULT_PARAMTERS; - setCommonParmsForDeployTests(parms); - parms.arguments.csdgroup = "12345678"; - - const bd = new BundleDeployer(parms); - const response = await bd.deployBundle(); - expect(response).toMatchSnapshot(); + let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const + parms = DEFAULT_PARAMTERS; + setCommonParmsForDeployTests(parms); + parms.arguments.csdgroup = "12345678"; + + const bd = new BundleDeployer(parms); + const response = await bd.deployBundle(); + expect(response).toMatchSnapshot(); } async function runUndeployTest() { - let parms: IHandlerParameters; - parms = DEFAULT_PARAMTERS; - setCommonParmsForUndeployTests(parms); - parms.arguments.csdgroup = "12345678"; - - const bd = new BundleDeployer(parms); - const response = await bd.undeployBundle(); - expect(response).toMatchSnapshot(); + let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const + parms = DEFAULT_PARAMTERS; + setCommonParmsForUndeployTests(parms); + parms.arguments.csdgroup = "12345678"; + + const bd = new BundleDeployer(parms); + const response = await bd.undeployBundle(); + expect(response).toMatchSnapshot(); } function setCommonParmsForDeployTests(parms: IHandlerParameters) { - setCommonParmsForUndeployTests(parms); - parms.arguments.bundledir = "1234567890"; - parms.arguments.targetstate = "ENABLED"; + setCommonParmsForUndeployTests(parms); + parms.arguments.bundledir = "1234567890"; + parms.arguments.targetstate = "ENABLED"; } function setCommonParmsForUndeployTests(parms: IHandlerParameters) { - parms.arguments.cicshlq = "12345678901234567890123456789012345"; - parms.arguments.cpsmhlq = "abcde12345abcde12345abcde12345abcde"; - parms.arguments.cicsplex = "12345678"; - parms.arguments.scope = "12345678"; - parms.arguments.csdgroup = undefined; - parms.arguments.resgroup = undefined; - parms.arguments.timeout = undefined; - parms.arguments.name = "12345678"; - parms.arguments.jobcard = "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"; - parms.arguments.targetstate = "DISCARDED"; - parms.arguments.description = undefined; - parms.arguments.zh = undefined; - parms.arguments.zp = undefined; - parms.arguments.zu = undefined; - parms.arguments.zpw = undefined; - parms.arguments.zru = undefined; - parms.arguments.zbp = undefined; + parms.arguments.cicshlq = "12345678901234567890123456789012345"; + parms.arguments.cpsmhlq = "abcde12345abcde12345abcde12345abcde"; + parms.arguments.cicsplex = "12345678"; + parms.arguments.scope = "12345678"; + parms.arguments.csdgroup = undefined; + parms.arguments.resgroup = undefined; + parms.arguments.timeout = undefined; + parms.arguments.name = "12345678"; + parms.arguments.jobcard = "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"; + parms.arguments.targetstate = "DISCARDED"; + parms.arguments.description = undefined; + parms.arguments.zh = undefined; + parms.arguments.zp = undefined; + parms.arguments.zu = undefined; + parms.arguments.zpw = undefined; + parms.arguments.zru = undefined; + parms.arguments.zbp = undefined; } async function testDeployJCL(parms: IHandlerParameters) { - submitSpy.mockImplementationOnce(() => [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + submitSpy.mockImplementationOnce(() => [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); - const bd = new BundleDeployer(parms); - const response = await bd.deployBundle(); + const bd = new BundleDeployer(parms); + const response = await bd.deployBundle(); - // Check the generated JCL - expect(submitSpy.mock.calls[submitSpy.mock.calls.length - 1][1]).toMatchSnapshot(); + // Check the generated JCL + expect(submitSpy.mock.calls[submitSpy.mock.calls.length - 1][1]).toMatchSnapshot(); } async function testUndeployJCL(parms: IHandlerParameters) { - submitSpy.mockImplementationOnce(() => [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2037I"}] ); + submitSpy.mockImplementationOnce(() => [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2037I"}] ); - const bd = new BundleDeployer(parms); - const response = await bd.undeployBundle(); + const bd = new BundleDeployer(parms); + const response = await bd.undeployBundle(); - // Check the generated JCL - expect(submitSpy.mock.calls[submitSpy.mock.calls.length - 1][1]).toMatchSnapshot(); + // Check the generated JCL + expect(submitSpy.mock.calls[submitSpy.mock.calls.length - 1][1]).toMatchSnapshot(); } diff --git a/__tests__/api/BundleDeploy/__snapshots__/BundleDeployer.test.ts.snap b/__tests__/api/BundleDeploy/__snapshots__/BundleDeployer.test.ts.snap index ec9d2e4a..d56006fe 100644 --- a/__tests__/api/BundleDeploy/__snapshots__/BundleDeployer.test.ts.snap +++ b/__tests__/api/BundleDeploy/__snapshots__/BundleDeployer.test.ts.snap @@ -621,7 +621,7 @@ exports[`BundleDeployer01 should undeploy successfully 1`] = `"Bundle undeployme exports[`BundleDeployer01 should update the progress bar 1`] = `"spoolOutput is not iterable"`; exports[`BundleDeployer01 tolerate embedded quote 1`] = ` -"//DFHDPLOY JOB DFHDPLOY,\\"some text\\",CLASS=A,MSGCLASS=X,TIME=NOLIMIT +"//DFHDPLOY JOB DFHDPLOY,"some text",CLASS=A,MSGCLASS=X,TIME=NOLIMIT //DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M //STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD // DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH @@ -678,7 +678,7 @@ DEPLOY BUNDLE(12345678) `; exports[`BundleDeployer01 tolerate quotes around jobcard with embedded quote 1`] = ` -"//DFHDPLOY JOB DFHDPLOY,\\"some text\\",CLASS=A,MSGCLASS=X,TIME=NOLIMIT +"//DFHDPLOY JOB DFHDPLOY,"some text",CLASS=A,MSGCLASS=X,TIME=NOLIMIT //DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M //STEPLIB DD DISP=SHR,DSN=12345678901234567890123456789012345.SDFHLOAD // DD DISP=SHR,DSN=abcde12345abcde12345abcde12345abcde.SEYUAUTH diff --git a/__tests__/api/BundlePush/BundlePusher.test.ts b/__tests__/api/BundlePush/BundlePusher.test.ts index 8a9deb0c..88a33224 100644 --- a/__tests__/api/BundlePush/BundlePusher.test.ts +++ b/__tests__/api/BundlePush/BundlePusher.test.ts @@ -12,8 +12,8 @@ import { BundlePusher } from "../../../src/api/BundlePush/BundlePusher"; import { IHandlerParameters, ImperativeError, IImperativeError, IProfile, Session } from "@zowe/imperative"; import * as cmci from "@zowe/cics-for-zowe-cli"; +import { getResource } from "@zowe/cics-for-zowe-cli"; import * as PushBundleDefinition from "../../../src/cli/push/bundle/PushBundle.definition"; -import * as fse from "fs-extra"; import * as fs from "fs"; import { ZosmfSession, SshSession, SubmitJobs, Shell, List, Upload, Create } from "@zowe/cli"; @@ -27,17 +27,17 @@ const DEFAULT_PARAMTERS: IHandlerParameters = { get: (type: string) => { if (profileError === true) { - throw new Error("Profile Error"); + throw new Error("Profile Error"); } if (type === "zosmf") { - return zosmfProfile; + return zosmfProfile; } if (type === "ssh") { - return sshProfile; + return sshProfile; } if (type === "cics") { - return cicsProfile; + return cicsProfile; } return {}; } @@ -70,10 +70,10 @@ const DEFAULT_PARAMTERS: IHandlerParameters = { positionals: [], }; const IS_DIRECTORY: any = { - isDirectory: jest.fn((directory) => (true)) + isDirectory: jest.fn((directory) => (true)) }; const IS_NOT_DIRECTORY: any = { - isDirectory: jest.fn((directory) => (false)) + isDirectory: jest.fn((directory) => (false)) }; let consoleText = ""; let zosmfProfile = {}; @@ -81,42 +81,52 @@ let sshProfile = {}; let cicsProfile = {}; let profileError = false; -let zosMFSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({})); -let sshSpy = jest.spyOn(SshSession, "createBasicSshSession").mockImplementation(() => ({})); -let createSpy = jest.spyOn(Create, "uss").mockImplementation(() => ({})); -let listSpy = jest.spyOn(List, "fileList").mockImplementation(() => ({})); -let membersSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ({})); -let submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => ({})); -let shellSpy = jest.spyOn(Shell, "executeSshCwd").mockImplementation(() => (0)); -let existsSpy = jest.spyOn(fs, "existsSync").mockImplementation(() => ({})); -let readSpy = jest.spyOn(fs, "readFileSync").mockImplementation(() => ({})); -let uploadSpy = jest.spyOn(Upload, "dirToUSSDirRecursive").mockImplementation(() => ({})); -let readdirSpy = jest.spyOn(fs, "readdirSync").mockImplementation(() => ({})); -let lstatSpy = jest.spyOn(fs, "lstatSync").mockImplementation(() => ({})); -let cmciSpy = jest.spyOn(cmci, "getResource").mockImplementation(() => ({})); +let zosMFSpy : jest.SpyInstance; +let sshSpy : jest.SpyInstance; +let createSpy : jest.SpyInstance; +let listSpy : jest.SpyInstance; +let membersSpy : jest.SpyInstance; +let submitSpy : jest.SpyInstance; +let shellSpy : jest.SpyInstance; +let existsSpy : jest.SpyInstance; +let readSpy : jest.SpyInstance; +let uploadSpy : jest.SpyInstance; +let readdirSpy : jest.SpyInstance; +let lstatSpy : jest.SpyInstance; +let cmciSpy : jest.SpyInstance; describe("BundlePusher01", () => { beforeEach(() => { + // @ts-ignore zosMFSpy = jest.spyOn(ZosmfSession, "createBasicZosmfSession").mockImplementation(() => ({})); + // @ts-ignore sshSpy = jest.spyOn(SshSession, "createBasicSshSession").mockImplementation(() => ({})); + // @ts-ignore createSpy = jest.spyOn(Create, "uss").mockImplementation(() => ({})); - listSpy = jest.spyOn(List, "fileList").mockImplementation(() => - ( { success: true, apiResponse: { items: [ ".", ".." ] } } )); + // @ts-ignore + listSpy = jest.spyOn(List, "fileList").mockImplementation(() => ( { success: true, apiResponse: { items: [ ".", ".." ] } } )); + // @ts-ignore membersSpy = jest.spyOn(List, "allMembers").mockImplementation(() => ( { val: "DFHDPLOY, EYU9ABSI" })); submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore shellSpy = jest.spyOn(Shell, "executeSshCwd").mockImplementation(() => (0)); existsSpy = jest.spyOn(fs, "existsSync").mockReturnValue(false); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return ""; - } + if (data.indexOf("cics.xml") > -1) { + return ""; + } }); + // @ts-ignore uploadSpy = jest.spyOn(Upload, "dirToUSSDirRecursive").mockImplementation(() => ({})); readdirSpy = jest.spyOn(fs, "readdirSync").mockImplementation(() => ([])); lstatSpy = jest.spyOn(fs, "lstatSync").mockImplementation(() => ( IS_NOT_DIRECTORY )); - cmciSpy = jest.spyOn(cmci, "getResource").mockImplementation(() => ({ response: { records: {} } })); + const cmciGetResource = { getResource }; + // @ts-ignore + cmciSpy = jest.spyOn(cmciGetResource, "getResource").mockImplementation(() => ({ response: { records: {} } })); consoleText = ""; zosmfProfile = { host: "wibble", user: "user", password: "thisIsntReal", port: 443, rejectUnauthorized: true }; sshProfile = { host: "wibble", user: "user", password: "thisIsntReal", port: 22 }; @@ -131,49 +141,49 @@ describe("BundlePusher01", () => { parms.arguments.name = undefined; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--name parameter is not set", parms); + "--name parameter is not set", parms); }); it("should complain with empty name", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.name = ""; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--name parameter is empty", parms); + "--name parameter is empty", parms); }); it("should complain with bad type for name", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.name = 0; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--name parameter is not a string", parms); + "--name parameter is not a string", parms); }); it("should complain with over long name", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.name = "123456789"; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--name parameter is too long", parms); + "--name parameter is too long", parms); }); it("should complain with missing targetdir", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.targetdir = undefined; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--targetdir parameter is not set", parms); + "--targetdir parameter is not set", parms); }); it("should complain with empty targetdir", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.targetdir = ""; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--targetdir parameter is empty", parms); + "--targetdir parameter is empty", parms); }); it("should complain with bad type for targetdir", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.targetdir = 0; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--targetdir parameter is not a string", parms); + "--targetdir parameter is not a string", parms); }); it("should complain with over long targetdir", async () => { const parms = getCommonParmsForPushTests(); @@ -184,22 +194,22 @@ describe("BundlePusher01", () => { "12345678901234567890123456789012345678901234567890123456"; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "--targetdir parameter is too long", parms); + "--targetdir parameter is too long", parms); }); it("should complain with bad manifest file", async () => { existsSpy.mockReturnValue(true); readSpy.mockImplementation((data: string) => ("wibble")); await runPushTestWithError("__tests__/__resources__/BadManifestBundle01", false, - "Existing CICS Manifest file found with unparsable content:"); + "Existing CICS Manifest file found with unparsable content:"); }); it("should complain with missing manifest file", async () => { readSpy.mockImplementationOnce(() => { - const e: any = new Error( "Injected read error" ); - e.code = "ENOENT"; - throw e; + const e: any = new Error( "Injected read error" ); + e.code = "ENOENT"; + throw e; }); await runPushTestWithError("__tests__/__resources__/EmptyBundle02", false, - "No bundle manifest file found:"); + "No bundle manifest file found:"); }); it("should complain with missing zOSMF profile for push", async () => { zosMFSpy.mockImplementationOnce(() => { throw new Error( "Injected zOSMF Create error" ); }); @@ -222,46 +232,49 @@ describe("BundlePusher01", () => { parms.arguments.zru = false; parms.arguments.zbp = "overrideBasePath"; zosMFSpy.mockImplementationOnce((profile: IProfile) => { - expect(profile.host).toMatch("overrideHost"); - expect(profile.port).toEqual(123); - expect(profile.user).toMatch("overrideUser"); - expect(profile.password).toMatch("overridePassword"); - expect(profile.rejectUnauthorized).toEqual(false); - expect(profile.basePath).toMatch("overrideBasePath"); + expect(profile.host).toMatch("overrideHost"); + // eslint-disable-next-line no-magic-numbers + expect(profile.port).toEqual(123); + expect(profile.user).toMatch("overrideUser"); + expect(profile.password).toMatch("overridePassword"); + expect(profile.rejectUnauthorized).toEqual(false); + expect(profile.basePath).toMatch("overrideBasePath"); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); }); it("should complain if zosmf-host notset" , async () => { zosmfProfile = undefined; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Required parameter --zosmf-host is not set."); + "Required parameter --zosmf-host is not set."); }); it("should complain if zosmf-user notset" , async () => { zosmfProfile = { host: "wibble", port: 443 }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Required parameter --zosmf-user is not set."); + "Required parameter --zosmf-user is not set."); }); it("should complain if zosmf-password notset" , async () => { zosmfProfile = { host: "wibble", port: 443, user: "user" }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Required parameter --zosmf-password is not set."); + "Required parameter --zosmf-password is not set."); }); it("should set default values if optional zosmf-* parameters notset" , async () => { zosmfProfile = { host: "wibble", user: "user", password: "thisIsntReal" }; const parms = getCommonParmsForPushTests(); zosMFSpy.mockImplementationOnce((profile: IProfile) => { - expect(profile.port).toEqual(443); - expect(profile.rejectUnauthorized).toEqual(true); + // eslint-disable-next-line no-magic-numbers + expect(profile.port).toEqual(443); + expect(profile.rejectUnauthorized).toEqual(true); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); + // eslint-disable-next-line no-magic-numbers expect(zosMFSpy).toHaveBeenCalledTimes(3); }); it("should complain with missing SSH profile for push", async () => { @@ -281,39 +294,42 @@ describe("BundlePusher01", () => { parms.arguments.skp = "overrideKeyPassphrase"; parms.arguments.sht = 555; sshSpy.mockImplementationOnce((profile: IProfile) => { - expect(profile.host).toMatch("overrideHost"); - expect(profile.port).toEqual(500); - expect(profile.user).toMatch("overrideUser"); - expect(profile.password).toMatch("overridePassword"); - expect(profile.privateKey).toMatch("overridePrivateKey"); - expect(profile.keyPassphrase).toMatch("overrideKeyPassphrase"); - expect(profile.handshakeTimeout).toEqual(555); + expect(profile.host).toMatch("overrideHost"); + // eslint-disable-next-line no-magic-numbers + expect(profile.port).toEqual(500); + expect(profile.user).toMatch("overrideUser"); + expect(profile.password).toMatch("overridePassword"); + expect(profile.privateKey).toMatch("overridePrivateKey"); + expect(profile.keyPassphrase).toMatch("overrideKeyPassphrase"); + // eslint-disable-next-line no-magic-numbers + expect(profile.handshakeTimeout).toEqual(555); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); }); it("should complain if ssh-host notset" , async () => { sshProfile = undefined; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Required parameter --ssh-host is not set."); + "Required parameter --ssh-host is not set."); }); it("should complain if ssh-user notset" , async () => { sshProfile = { host: "wibble", port: 22 }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Required parameter --ssh-user is not set."); + "Required parameter --ssh-user is not set."); }); it("should set default values if optional ssh-* parameters notset" , async () => { sshProfile = { host: "wibble", user: "user", password: "thisIsntReal" }; const parms = getCommonParmsForPushTests(); sshSpy.mockImplementationOnce((profile: IProfile) => { - expect(profile.port).toEqual(22); + // eslint-disable-next-line no-magic-numbers + expect(profile.port).toEqual(22); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(sshSpy).toHaveBeenCalledTimes(1); }); @@ -328,18 +344,18 @@ describe("BundlePusher01", () => { parms.arguments.cru = "false"; parms.arguments.cpr = "https"; cmciSpy.mockImplementationOnce((session: Session) => { - // CMCI errors aren't propagated, so log the output details - const info = session.ISession; - parms.response.console.log("HOST: " + info.hostname); - parms.response.console.log("PORT: " + info.port); - parms.response.console.log("USER: " + info.user); - parms.response.console.log("PASSWORD: " + info.password); - parms.response.console.log("REJECT: " + info.rejectUnauthorized); - parms.response.console.log("PROTOCOL: " + info.protocol); + // CMCI errors aren't propagated, so log the output details + const info = session.ISession; + parms.response.console.log("HOST: " + info.hostname); + parms.response.console.log("PORT: " + info.port); + parms.response.console.log("USER: " + info.user); + parms.response.console.log("PASSWORD: " + info.password); + parms.response.console.log("REJECT: " + info.rejectUnauthorized); + parms.response.console.log("PROTOCOL: " + info.protocol); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(cmciSpy).toHaveBeenCalledTimes(1); expect(consoleText).toContain("HOST: overrideHost"); @@ -353,34 +369,34 @@ describe("BundlePusher01", () => { cicsProfile = { user: "user", port: 1490, password: "thisIsntReal" }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Partial cics plug-in configuration encountered, --cics-host is not set."); + "Partial cics plug-in configuration encountered, --cics-host is not set."); }); it("should complain if cics configured and cics-user notset" , async () => { cicsProfile = { host: "wibble", port: 1490, password: "thisIsntReal" }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Partial cics plug-in configuration encountered, --cics-user is not set."); + "Partial cics plug-in configuration encountered, --cics-user is not set."); }); it("should complain if cics configured and cics-password notset" , async () => { cicsProfile = { host: "wibble", port: 1490, user: "user" }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Partial cics plug-in configuration encountered, --cics-password is not set."); + "Partial cics plug-in configuration encountered, --cics-password is not set."); }); it("should set default values if optional cics-* parameters notset" , async () => { cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal" }; const parms = getCommonParmsForPushTests(); cmciSpy.mockImplementationOnce((session: Session) => { - // CMCI errors aren't propagated, so log the output details - const info = session.ISession; - parms.response.console.log("PORT: " + info.port + "\n"); - parms.response.console.log("REJECT: " + info.rejectUnauthorized + "\n"); - parms.response.console.log("PROTOCOL: " + info.protocol + "\n"); + // CMCI errors aren't propagated, so log the output details + const info = session.ISession; + parms.response.console.log("PORT: " + info.port + "\n"); + parms.response.console.log("REJECT: " + info.rejectUnauthorized + "\n"); + parms.response.console.log("PROTOCOL: " + info.protocol + "\n"); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(cmciSpy).toHaveBeenCalledTimes(1); expect(consoleText).toContain("PROTOCOL: http\n"); @@ -393,7 +409,7 @@ describe("BundlePusher01", () => { parms.arguments.sh = "wobble"; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(consoleText).toContain("WARNING: --ssh-host value 'wobble' does not match --zosmf-host value 'wibble'."); }); it("should not complain with matching zOSMF and SSH profile host names", async () => { @@ -402,21 +418,21 @@ describe("BundlePusher01", () => { parms.arguments.sh = "wibble"; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(consoleText).not.toContain("WARNING: --ssh-host"); }); it("should complain with mismatching zOSMF and CICS profile host names", async () => { cicsProfile = { host: "different", port: 1490, user: "user", password: "thisIsntReal" }; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).toContain("WARNING: --cics-host value 'different' does not match --zosmf-host value 'wibble'."); }); it("should not complain with matching zOSMF and CICS profile host names", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).not.toContain("WARNING: --cics-host"); }); it("should complain with mismatching zOSMF and SSH profile user names", async () => { @@ -425,7 +441,7 @@ describe("BundlePusher01", () => { parms.arguments.su = "joe"; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(consoleText).toContain("WARNING: --ssh-user value 'joe' does not match --zosmf-user value 'fred'."); }); it("should not complain with matching zOSMF and SSH profile user names", async () => { @@ -434,7 +450,7 @@ describe("BundlePusher01", () => { parms.arguments.su = "fred"; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(consoleText).not.toContain("WARNING: --ssh-user"); }); it("should not complain with matching zOSMF and SSH profile user names - case", async () => { @@ -443,14 +459,14 @@ describe("BundlePusher01", () => { parms.arguments.su = "FRED"; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed", parms); + "PUSH operation completed", parms); expect(consoleText).not.toContain("WARNING: --ssh-user"); }); it("should complain with mismatching zOSMF and CICS profile user names", async () => { cicsProfile = { host: "wibble", port: 1490, user: "joe", password: "fakePassword" }; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).toContain("WARNING: --cics-user value 'joe' does not match --zosmf-user value 'user'."); }); it("should complain with mismatching zOSMF and SSH profile passwords", async () => { @@ -459,7 +475,7 @@ describe("BundlePusher01", () => { parms.arguments.spw = "fakeSshPassword"; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Different passwords are specified for the same user ID in the zosmf and ssh configurations.", parms); + "Different passwords are specified for the same user ID in the zosmf and ssh configurations.", parms); expect(consoleText).not.toContain("fakeZosmfPassword"); expect(consoleText).not.toContain("fakeSshPassword"); @@ -468,7 +484,7 @@ describe("BundlePusher01", () => { sshProfile = { host: "wibble", user: "fred", privateKey: "fakeSshKey", port: 22 }; await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).not.toContain("thisIsntReal"); expect(consoleText).not.toContain("fakeSshKey"); @@ -477,7 +493,7 @@ describe("BundlePusher01", () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "fakePassword2" }; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Different passwords are specified for the same user ID in the zosmf and cics configurations."); + "Different passwords are specified for the same user ID in the zosmf and cics configurations."); expect(consoleText).not.toContain("thisIsntReal"); expect(consoleText).not.toContain("fakePassword2"); @@ -485,7 +501,7 @@ describe("BundlePusher01", () => { it("should complain if remote bundle dir mkdir fails", async () => { createSpy.mockImplementationOnce(() => { throw new Error( "Injected Create error" ); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred attempting to create directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Create error"); + "A problem occurred attempting to create directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Create error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -493,12 +509,12 @@ describe("BundlePusher01", () => { }); it("should complain if remote target dir can't be found (string)", async () => { createSpy.mockImplementationOnce(() => { - const cause = "{ \"category\": 8, \"rc\": -1, \"reason\": 93651005 }"; - const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; - throw new ImperativeError(impError); + const cause = "{ \"category\": 8, \"rc\": -1, \"reason\": 93651005 }"; + const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; + throw new ImperativeError(impError); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "The target directory does not exist, consider creating it by issuing: \nzowe zos-uss issue ssh \"mkdir -p /u/ThisDoesNotExist\""); + "The target directory does not exist, consider creating it by issuing: \nzowe zos-uss issue ssh \"mkdir -p /u/ThisDoesNotExist\""); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -506,12 +522,12 @@ describe("BundlePusher01", () => { }); it("should complain if remote target dir can't be found (object)", async () => { createSpy.mockImplementationOnce(() => { - const cause = { category: 8, rc: -1, reason: 93651005 }; - const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; - throw new ImperativeError(impError); + const cause = { category: 8, rc: -1, reason: 93651005 }; + const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; + throw new ImperativeError(impError); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "The target directory does not exist, consider creating it by issuing: \nzowe zos-uss issue ssh \"mkdir -p /u/ThisDoesNotExist\""); + "The target directory does not exist, consider creating it by issuing: \nzowe zos-uss issue ssh \"mkdir -p /u/ThisDoesNotExist\""); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -519,12 +535,12 @@ describe("BundlePusher01", () => { }); it("should complain if remote target dir fails without cause object", async () => { createSpy.mockImplementationOnce(() => { - const cause = "This is a text message cause"; - const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; - throw new ImperativeError(impError); + const cause = "This is a text message cause"; + const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; + throw new ImperativeError(impError); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred attempting to create directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Create error"); + "A problem occurred attempting to create directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Create error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -532,12 +548,12 @@ describe("BundlePusher01", () => { }); it("should complain if remote bundle dir not auth", async () => { createSpy.mockImplementationOnce(() => { - const cause = "{ \"category\": 8, \"rc\": -1, \"reason\": -276865003 }"; - const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; - throw new ImperativeError(impError); + const cause = "{ \"category\": 8, \"rc\": -1, \"reason\": -276865003 }"; + const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; + throw new ImperativeError(impError); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "You are not authorized to create the target bundle directory '/u/ThisDoesNotExist/12345678'."); + "You are not authorized to create the target bundle directory '/u/ThisDoesNotExist/12345678'."); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -545,12 +561,12 @@ describe("BundlePusher01", () => { }); it("should not complain if remote bundle dir already exists", async () => { createSpy.mockImplementationOnce(() => { - const cause = "{ \"category\": 1, \"rc\": 4, \"reason\": 19 }"; - const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; - throw new ImperativeError(impError); + const cause = "{ \"category\": 1, \"rc\": 4, \"reason\": 19 }"; + const impError: IImperativeError = { msg: "Injected Create error", causeErrors: cause }; + throw new ImperativeError(impError); }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, - "PUSH operation completed"); + "PUSH operation completed"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -568,7 +584,7 @@ describe("BundlePusher01", () => { it("should complain if remote bundledir list fails", async () => { listSpy.mockImplementationOnce(() => ( { success: false } )); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command Failed."); + "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command Failed."); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -578,7 +594,7 @@ describe("BundlePusher01", () => { it("should complain if remote bundledir list returns empty response", async () => { listSpy.mockImplementationOnce(() => ( { success: true, apiResponse: undefined } )); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command response is empty."); + "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command response is empty."); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -588,7 +604,7 @@ describe("BundlePusher01", () => { it("should complain if remote bundledir list returns empty items", async () => { listSpy.mockImplementationOnce(() => ( { success: true, apiResponse: {} } )); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command response items are missing."); + "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: Command response items are missing."); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -597,9 +613,9 @@ describe("BundlePusher01", () => { }); it("should complain if remote bundledir exists and is not a Bundle", async () => { listSpy.mockImplementationOnce(() => - ( { success: true, apiResponse: { items: [ {name: "."}, {name: ".."}, {name: "wibble"} ] } } )); + ( { success: true, apiResponse: { items: [ {name: "."}, {name: ".."}, {name: "wibble"} ] } } )); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: " + + "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: " + "The remote directory is already populated and does not contain a bundle."); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -609,9 +625,9 @@ describe("BundlePusher01", () => { }); it("should complain if remote bundledir is not empty and --overwrite not set", async () => { listSpy.mockImplementationOnce(() => - ( { success: true, apiResponse: { items: [ {name: "."}, {name: ".."}, {name: "META-INF"} ] } } )); + ( { success: true, apiResponse: { items: [ {name: "."}, {name: ".."}, {name: "META-INF"} ] } } )); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: " + + "A problem occurred accessing remote bundle directory '/u/ThisDoesNotExist/12345678'. Problem is: " + "The remote directory has existing content and --overwrite has not been set."); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -623,7 +639,7 @@ describe("BundlePusher01", () => { submitSpy.mockImplementationOnce(() => { throw new Error( "Injected Submit error" ); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "Submitting DFHDPLOY JCL for the UNDEPLOY action"); + "Submitting DFHDPLOY JCL for the UNDEPLOY action"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -634,16 +650,17 @@ describe("BundlePusher01", () => { }); it("should uninstall node modules", async () => { readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); expect(createSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); + // eslint-disable-next-line no-magic-numbers expect(shellSpy).toHaveBeenCalledTimes(3); expect(membersSpy).toHaveBeenCalledTimes(2); expect(submitSpy).toHaveBeenCalledTimes(2); @@ -651,17 +668,18 @@ describe("BundlePusher01", () => { }); it("should cope with error uninstalling node modules", async () => { readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); shellSpy.mockImplementationOnce(() => { throw new Error( "Injected Shell error from npm uninstall" ); }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); expect(createSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); + // eslint-disable-next-line no-magic-numbers expect(shellSpy).toHaveBeenCalledTimes(3); expect(membersSpy).toHaveBeenCalledTimes(2); expect(submitSpy).toHaveBeenCalledTimes(2); @@ -671,7 +689,8 @@ describe("BundlePusher01", () => { shellSpy.mockImplementationOnce(() => { throw new Error( "Injected Shell error" ); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Shell error"); + "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' " + + "in remote directory '/u/ThisDoesNotExist/12345678'. Problem is: Injected Shell error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -683,12 +702,12 @@ describe("BundlePusher01", () => { }); it("should tolerate delete of empty directory", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("FSUM9195 cannot unlink entry \"*\": EDC5129I No such file or directory."); - return 1; + stdoutHandler("FSUM9195 cannot unlink entry \"*\": EDC5129I No such file or directory."); + return 1; }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -700,12 +719,12 @@ describe("BundlePusher01", () => { }); it("should not tolerate non zero return code from ssh command", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Ssh command exit with non zero status"); - return 1; + stdoutHandler("Ssh command exit with non zero status"); + return 1; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + + "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + "Problem is: The output from the remote command implied that an error occurred, return code 1."); expect(consoleText).toContain("Ssh command exit with non zero status"); @@ -719,12 +738,13 @@ describe("BundlePusher01", () => { }); it("should not tolerate mixture of FSUM9195 but exit status is not 1", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected FSUM9195 error message"); - return 127; + stdoutHandler("Injected FSUM9195 error message"); + // eslint-disable-next-line no-magic-numbers + return 127; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + + "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + "Problem is: The output from the remote command implied that an error occurred, return code 127"); expect(consoleText).toContain("Injected FSUM9195 error message"); @@ -738,12 +758,12 @@ describe("BundlePusher01", () => { }); it("should not tolerate mixture of FSUM9195 and other FSUM messages", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected FSUM9195 and FSUM9196 error message"); - return 1; + stdoutHandler("Injected FSUM9195 and FSUM9196 error message"); + return 1; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + + "A problem occurred attempting to run 'if [ \"$(ls)\" ]; then rm -r *; fi' in remote directory '/u/ThisDoesNotExist/12345678'. " + "Problem is: The output from the remote command implied that an error occurred, return code 1."); expect(consoleText).toContain("Injected FSUM9195 and FSUM9196 error message"); @@ -757,21 +777,21 @@ describe("BundlePusher01", () => { }); it("should handle error with attribs file", async () => { existsSpy.mockImplementation((data: string) => { - if (data.indexOf(".zosattributes") > -1) { - return true; - } + if (data.indexOf(".zosattributes") > -1) { + return true; + } }); readSpy.mockImplementation((data: string) => { - if (data.indexOf(".zosattributes") > -1) { - throw new Error("Injected Read File error"); - } - else if (data.indexOf("cics.xml") > -1) { - return ""; - } + if (data.indexOf(".zosattributes") > -1) { + throw new Error("Injected Read File error"); + } + else if (data.indexOf("cics.xml") > -1) { + return ""; + } }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", true, - "Problem is: Injected Read File error"); + "Problem is: Injected Read File error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -785,21 +805,21 @@ describe("BundlePusher01", () => { }); it("should load zosattribs file", async () => { existsSpy.mockImplementation((data: string) => { - if (data.indexOf(".zosattributes") > -1) { - return true; - } + if (data.indexOf(".zosattributes") > -1) { + return true; + } }); readSpy.mockImplementation((data: string) => { - if (data.indexOf(".zosattributes") > -1) { - return ""; - } - else if (data.indexOf("cics.xml") > -1) { - return ""; - } + if (data.indexOf(".zosattributes") > -1) { + return ""; + } + else if (data.indexOf("cics.xml") > -1) { + return ""; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).not.toContain("WARNING: No .zosattributes file found in the bundle directory, default values will be applied."); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -814,7 +834,7 @@ describe("BundlePusher01", () => { }); it("should use a default zosattribs file", async () => { await runPushTest("__tests__/__resources__/ExampleBundle01", true, - "PUSH operation completed"); + "PUSH operation completed"); expect(consoleText).toContain("WARNING: No .zosattributes file found in the bundle directory, default values will be applied."); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -831,7 +851,7 @@ describe("BundlePusher01", () => { uploadSpy.mockImplementationOnce(() => { throw new Error("Injected upload error"); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred uploading the bundle contents to the remote directory " + + "A problem occurred uploading the bundle contents to the remote directory " + "'/u/ThisDoesNotExist/12345678'. Problem is: Injected upload error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -848,13 +868,13 @@ describe("BundlePusher01", () => { it("should handle custom bundle id", async () => { uploadSpy.mockImplementationOnce(() => { throw new Error("Injected upload error"); }); readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return ""; - } + if (data.indexOf("cics.xml") > -1) { + return ""; + } }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred uploading the bundle contents to the remote directory " + + "A problem occurred uploading the bundle contents to the remote directory " + "'/u/ThisDoesNotExist/InjectedBundleId_1.0.0'. Problem is: Injected upload error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -871,14 +891,14 @@ describe("BundlePusher01", () => { it("should handle custom bundle id and version", async () => { uploadSpy.mockImplementationOnce(() => { throw new Error("Injected upload error"); }); readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return " -1) { + return ""; - } + } }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred uploading the bundle contents to the remote directory " + + "A problem occurred uploading the bundle contents to the remote directory " + "'/u/ThisDoesNotExist/InjectedBundleId_33.22.11'. Problem is: Injected upload error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -894,19 +914,19 @@ describe("BundlePusher01", () => { }); it("should handle error with remote npm install", async () => { shellSpy.mockImplementation((session: any, cmd: string) => { - if (cmd.indexOf("npm install") > -1) { - throw new Error("Injected NPM error"); - } - else { - return true; - } + if (cmd.indexOf("npm install") > -1) { + throw new Error("Injected NPM error"); + } + else { + return true; + } }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Problem is: Injected NPM error"); + "Problem is: Injected NPM error"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); @@ -923,20 +943,20 @@ describe("BundlePusher01", () => { }); it("should handle failure of remote npm install", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - if (cmd.indexOf("npm install") > -1) { - stdoutHandler("Injected stdout error message"); - return 1; - } - else { - return true; - } + if (cmd.indexOf("npm install") > -1) { + stdoutHandler("Injected stdout error message"); + return 1; + } + else { + return true; + } }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + + "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + " && export _BPXK_AUTOCVT=ON && npm install' in remote directory '/u/ThisDoesNotExist/12345678'." + " Problem is: The output from the remote command implied that an error occurred, return code 1."); @@ -956,20 +976,20 @@ describe("BundlePusher01", () => { }); it("should handle failure of remote npm install with FSUM message", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - if (cmd.indexOf("npm install") > -1) { - stdoutHandler("Injected FSUM7351 not found message"); - return 1; - } - else { - return true; - } + if (cmd.indexOf("npm install") > -1) { + stdoutHandler("Injected FSUM7351 not found message"); + return 1; + } + else { + return true; + } }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + + "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + " && export _BPXK_AUTOCVT=ON && npm install' in remote directory '/u/ThisDoesNotExist/12345678'." + " Problem is: The output from the remote command implied that an error occurred, return code 1."); @@ -989,20 +1009,20 @@ describe("BundlePusher01", () => { }); it("should handle failure of remote npm install with node error", async () => { shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - if (cmd.indexOf("npm install") > -1) { - stdoutHandler("Injected npm ERR! Exit status 1 message"); - return 1; - } - else { - return true; - } + if (cmd.indexOf("npm install") > -1) { + stdoutHandler("Injected npm ERR! Exit status 1 message"); + return 1; + } + else { + return true; + } }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + + "A problem occurred attempting to run 'export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\"" + " && export _BPXK_AUTOCVT=ON && npm install' in remote directory '/u/ThisDoesNotExist/12345678'." + " Problem is: The output from the remote command implied that an error occurred, return code 1."); @@ -1024,7 +1044,7 @@ describe("BundlePusher01", () => { submitSpy.mockImplementationOnce(() => { throw new Error("Injected deploy error"); }); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "Failure occurred submitting DFHDPLOY JCL for jobid UNKNOWN: 'Injected deploy error'. " + + "Failure occurred submitting DFHDPLOY JCL for jobid UNKNOWN: 'Injected deploy error'. " + "Most recent status update: 'Submitting DFHDPLOY JCL for the DEPLOY action'."); expect(zosMFSpy).toHaveBeenCalledTimes(1); @@ -1058,11 +1078,11 @@ describe("BundlePusher01", () => { parms.arguments.verbose = true; parms.arguments.targetdir = "//u//escapedDirName"; shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected stdout shell message"); - return 0; + stdoutHandler("Injected stdout shell message"); + return 0; }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed", parms); @@ -1084,42 +1104,42 @@ describe("BundlePusher01", () => { it("should set up auto conversion before running npm install", async () => { readdirSpy.mockImplementation((data: string) => { return [ "package.json" ]; - }); + }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); expect(shellSpy).toBeCalledWith(expect.anything(), - expect.stringContaining("_BPXK_AUTOCVT=ON"), - expect.anything(), - expect.anything()); + expect.stringContaining("_BPXK_AUTOCVT=ON"), + expect.anything(), + expect.anything()); }); it("should run npm install for each package.json", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.verbose = true; parms.arguments.targetdir = "//u//escapedDirName"; shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected stdout shell message for " + dir); - return 0; + stdoutHandler("Injected stdout shell message for " + dir); + return 0; }); readdirSpy.mockImplementation((data: string) => { - if (data.endsWith("XXXDIRXXX")) { - return ["file.XXX.1", "package.json", "ZZZDIRZZZ"]; - } - if (data.endsWith("YYYDIRYYY")) { - return [ "file.YYY.1"]; - } - if (data.endsWith("ZZZDIRZZZ")) { - return ["package.json"]; - } - if (data.endsWith("node_modules")) { - return ["package.json"]; - } - return [ "file.1", "file.2", "XXXDIRXXX", "YYYDIRYYY", "node_modules" ]; + if (data.endsWith("XXXDIRXXX")) { + return ["file.XXX.1", "package.json", "ZZZDIRZZZ"]; + } + if (data.endsWith("YYYDIRYYY")) { + return [ "file.YYY.1"]; + } + if (data.endsWith("ZZZDIRZZZ")) { + return ["package.json"]; + } + if (data.endsWith("node_modules")) { + return ["package.json"]; + } + return [ "file.1", "file.2", "XXXDIRXXX", "YYYDIRYYY", "node_modules" ]; }); lstatSpy.mockImplementation((data: string) => { - if (data.endsWith("XXXDIRXXX") || data.endsWith("YYYDIRYYY") || data.endsWith("ZZZDIRZZZ") || + if (data.endsWith("XXXDIRXXX") || data.endsWith("YYYDIRYYY") || data.endsWith("ZZZDIRZZZ") || data.endsWith("node_modules")) { - return IS_DIRECTORY; - } - return IS_NOT_DIRECTORY; + return IS_DIRECTORY; + } + return IS_NOT_DIRECTORY; }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed", parms); @@ -1137,18 +1157,20 @@ describe("BundlePusher01", () => { expect(existsSpy).toHaveBeenCalledTimes(1); expect(readSpy).toHaveBeenCalledTimes(1); expect(uploadSpy).toHaveBeenCalledTimes(1); + // eslint-disable-next-line no-magic-numbers expect(readdirSpy).toHaveBeenCalledTimes(4); + // eslint-disable-next-line no-magic-numbers expect(lstatSpy).toHaveBeenCalledTimes(10); }); it("should run to completion with verbose output", async () => { const parms = getCommonParmsForPushTests(); parms.arguments.verbose = true; shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected stdout shell message"); - return 0; + stdoutHandler("Injected stdout shell message"); + return 0; }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed", parms); @@ -1179,11 +1201,11 @@ describe("BundlePusher01", () => { const parms = getCommonParmsForPushTests(); parms.arguments.verbose = true; shellSpy.mockImplementation((session: any, cmd: string, dir: string, stdoutHandler: (data: string) => void) => { - stdoutHandler("Injected stdout shell message"); - return 0; + stdoutHandler("Injected stdout shell message"); + return 0; }); readdirSpy.mockImplementation((data: string) => { - return [ "package.json" ]; + return [ "package.json" ]; }); await runPushTest("__tests__/__resources__/ExampleBundle01", true, "PUSH operation completed", parms); @@ -1205,6 +1227,7 @@ describe("BundlePusher01", () => { expect(sshSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); expect(createSpy).toHaveBeenCalledTimes(1); + // eslint-disable-next-line no-magic-numbers expect(shellSpy).toHaveBeenCalledTimes(3); expect(membersSpy).toHaveBeenCalledTimes(2); expect(submitSpy).toHaveBeenCalledTimes(2); @@ -1216,8 +1239,10 @@ describe("BundlePusher01", () => { expect(cmciSpy).toHaveBeenCalledTimes(0); }); it("should cope with a NODEJSAPP in the bundle but no CICS profile specified", async () => { + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1235,8 +1260,10 @@ describe("BundlePusher01", () => { }); it("should cope with a NODEJSAPP in the bundle with a CICS profile specified", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1255,26 +1282,26 @@ describe("BundlePusher01", () => { it("should query scope even with no NODEJSAPPs", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, regionData: cmci.IResourceParms) => { - if (regionData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + if (regionData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1296,8 +1323,10 @@ describe("BundlePusher01", () => { }); it("should cope with a NODEJSAPP in the bundle with a CICS profile specified and --verbose", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); const parms = getCommonParmsForPushTests(); parms.arguments.verbose = true; @@ -1325,36 +1354,39 @@ describe("BundlePusher01", () => { }); it("should generate diagnostics even if deploy fails", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I DFHRL2067W"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I DFHRL2067W"}] ); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, regionData: cmci.IResourceParms) => { - if (regionData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + if (regionData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); const parms = getCommonParmsForPushTests(); parms.arguments.verbose = true; await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "DFHDPLOY stopped processing for jobid UNKNOWN due to an error.", parms); + "DFHDPLOY stopped processing for jobid UNKNOWN due to an error.", parms); expect(consoleText).toContain("Making remote bundle directory '/u/ThisDoesNotExist/12345678'"); expect(consoleText).toContain("Accessing contents of remote bundle directory"); @@ -1367,7 +1399,8 @@ describe("BundlePusher01", () => { expect(consoleText).toContain("Regions in scope '12345678' of CICSplex '12345678':"); expect(consoleText).toContain("Applid: ABCDEFG jobname: MYCICS jobid: JOB12345 sysname: ABCD"); expect(consoleText).toContain("Querying NODEJSAPP resources over CMCI"); - expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 --criteria \"BUNDLE=12345678\" --cics-plex 12345678"); + expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 " + + "--criteria \"BUNDLE=12345678\" --cics-plex 12345678"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); @@ -1382,8 +1415,10 @@ describe("BundlePusher01", () => { }); it("should tolerate a Node.js diagnostics generation failure - region", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP"}] ); cmciSpy.mockImplementationOnce(() => { throw new Error("Injected CMCI GET error"); }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1403,37 +1438,41 @@ describe("BundlePusher01", () => { }); it("should tolerate a Node.js diagnostics generation failure - nodejsapp", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { - if (nodejsData.name === "CICSNodejsapp") { - throw new Error("Injected CMCI GET error"); - } - else if (nodejsData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + if (nodejsData.name === "CICSNodejsapp") { + throw new Error("Injected CMCI GET error"); + } + else if (nodejsData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); - expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 --criteria \"BUNDLE=12345678\" --cics-plex 12345678"); + expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 " + + "--criteria \"BUNDLE=12345678\" --cics-plex 12345678"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); @@ -1448,37 +1487,41 @@ describe("BundlePusher01", () => { }); it("should tolerate a Node.js diagnostics generation failure - nodejsapp empty", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { - if (nodejsData.name === "CICSNodejsapp") { - return {}; - } - else if (nodejsData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + if (nodejsData.name === "CICSNodejsapp") { + return {}; + } + else if (nodejsData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); - expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 --criteria \"BUNDLE=12345678\" --cics-plex 12345678"); + expect(consoleText).toContain("zowe cics get resource CICSNodejsapp --region-name 12345678 " + + "--criteria \"BUNDLE=12345678\" --cics-plex 12345678"); expect(zosMFSpy).toHaveBeenCalledTimes(1); expect(sshSpy).toHaveBeenCalledTimes(1); expect(listSpy).toHaveBeenCalledTimes(1); @@ -1493,39 +1536,42 @@ describe("BundlePusher01", () => { }); it("should generate Node.js diagnostics for 1 enabled NODEJSAPP", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { - if (nodejsData.name === "CICSNodejsapp") { - return { response: { - records: { - cicsnodejsapp: { - name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" - } + if (nodejsData.name === "CICSNodejsapp") { + return { response: { + records: { + cicsnodejsapp: { + name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" + } + } } - } - }; - } - else if (nodejsData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + }; + } + else if (nodejsData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1550,39 +1596,42 @@ describe("BundlePusher01", () => { }); it("should generate Node.js diagnostics for 1 disabled NODEJSAPP", async () => { cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + + if (data.indexOf("cics.xml") > -1) { + return "" + "" + ""; - } + } }); cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { - if (nodejsData.name === "CICSNodejsapp") { - return { response: { - records: { - cicsnodejsapp: { - name: "name", pid: "0", enablestatus: "DISABLED", stderr: "", stdout: "", eyu_cicsname: "1" - } + if (nodejsData.name === "CICSNodejsapp") { + return { response: { + records: { + cicsnodejsapp: { + name: "name", pid: "0", enablestatus: "DISABLED", stderr: "", stdout: "", eyu_cicsname: "1" + } + } } - } - }; - } - else if (nodejsData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: { - applid: "ABCD", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + }; + } + else if (nodejsData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: { + applid: "ABCD", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1606,51 +1655,54 @@ describe("BundlePusher01", () => { expect(cmciSpy).toHaveBeenCalledTimes(2); }); it("should generate Node.js diagnostics for 2 NODEJSAPPs", async () => { + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2012I"}] ); cicsProfile = { host: "wibble", port: 1490, user: "user", password: "thisIsntReal" }; + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { - if (data.indexOf("cics.xml") > -1) { - return "" + - "" + - "" + - ""; - } + if (data.indexOf("cics.xml") > -1) { + return "" + + "" + + "" + + ""; + } }); cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { - if (nodejsData.name === "CICSNodejsapp") { - return { response: { - records: { - cicsnodejsapp: [ - { - name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" - }, - { - name: "name2", pid: "33", enablestatus: "ENABLED", stderr: "/tmp/name2err", stdout: "/tmp/name2out", eyu_cicsname: "1" + if (nodejsData.name === "CICSNodejsapp") { + return { response: { + records: { + cicsnodejsapp: [ + { + name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" + }, + { + name: "name2", pid: "33", enablestatus: "ENABLED", stderr: "/tmp/name2err", stdout: "/tmp/name2out", eyu_cicsname: "1" + } + ] } - ] } - } - }; - } - else if (nodejsData.name === "CICSRegion") { - return { response: { - records: { - cicsregion: [ - { - applid: "ABCD", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - }, - { - applid: "EFGHIHJK", jobid: "JOB54321", jobname: "MYCICS2", mvssysname: "EFGH" - }, - ] + }; + } + else if (nodejsData.name === "CICSRegion") { + return { response: { + records: { + cicsregion: [ + { + applid: "ABCD", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + }, + { + applid: "EFGHIHJK", jobid: "JOB54321", jobname: "MYCICS2", mvssysname: "EFGH" + }, + ] + } } - } - }; - } - else { - return {}; - } + }; + } + else { + return {}; + } }); await runPushTest("__tests__/__resources__/ExampleBundle01", false, "PUSH operation completed"); @@ -1679,34 +1731,37 @@ describe("BundlePusher01", () => { }); it("should not attempt to generate diagnostics for NODEJSAPPs if bundle does not install", async () => { + // @ts-ignore readSpy = jest.spyOn(fs, "readFileSync").mockImplementation((data: string) => { if (data.indexOf("cics.xml") > -1) { - return "" + - "" + - ""; + return "" + + "" + + ""; } - }); + }); + // @ts-ignore submitSpy = jest.spyOn(SubmitJobs, "submitJclString").mockImplementation(() => - [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I"}] ); + // @ts-ignore + [{ddName: "SYSTSPRT", stepName: "DFHDPLOY", data: "DFHRL2055I"}] ); cicsProfile = { host: "wibble", user: "user", password: "thisIsntReal", cicsPlex: "12345678", regionName: "12345678" }; cmciSpy.mockImplementation((cicsSession: any, nodejsData: cmci.IResourceParms) => { if (nodejsData.name === "CICSRegion") { return { response: { records: { - cicsregion: { - applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" - } + cicsregion: { + applid: "ABCDEFG", jobid: "JOB12345", jobname: "MYCICS", mvssysname: "ABCD" + } } } }; } else if (nodejsData.name === "CICSNodejsapp") { return { response: { records: { - cicsnodejsapp: [{ - name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" - }] + cicsnodejsapp: [{ + name: "name", pid: "22", enablestatus: "ENABLED", stderr: "/tmp/stderr", stdout: "/tmp/stdout", eyu_cicsname: "1" + }] } - } + } }; } else { return {}; @@ -1716,7 +1771,7 @@ describe("BundlePusher01", () => { const parms = getCommonParmsForPushTests(); await runPushTestWithError("__tests__/__resources__/ExampleBundle01", false, - "DFHDPLOY stopped processing for jobid UNKNOWN due to an error.", parms); + "DFHDPLOY stopped processing for jobid UNKNOWN due to an error.", parms); expect(consoleText).toContain("Gathering scope information"); expect(consoleText).toContain("Querying regions in scope over CMCI"); @@ -1729,81 +1784,82 @@ describe("BundlePusher01", () => { }); async function runPushTestWithError(localBundleDir: string, overwrite: boolean, errorText: string, parmsIn?: IHandlerParameters) { - let parms: IHandlerParameters; - if (parmsIn === undefined) { - parms = getCommonParmsForPushTests(); - } - else { - parms = parmsIn; - } - parms.arguments.overwrite = overwrite; - - let err: Error; - try { - const bp = new BundlePusher(parms, localBundleDir); - const response = await bp.performPush(); - } catch (e) { - err = e; - } - expect(err).toBeDefined(); - expect(err.message).toContain(errorText); + let parms: IHandlerParameters; + if (parmsIn === undefined) { + parms = getCommonParmsForPushTests(); + } + else { + parms = parmsIn; + } + parms.arguments.overwrite = overwrite; + + let err: Error; + try { + const bp = new BundlePusher(parms, localBundleDir); + const response = await bp.performPush(); + } catch (e) { + err = e; + } + expect(err).toBeDefined(); + expect(err.message).toContain(errorText); } async function runPushTest(localBundleDir: string, overwrite: boolean, expectedResponse: string, parmsIn?: IHandlerParameters) { - let parms: IHandlerParameters; - if (parmsIn === undefined) { - parms = getCommonParmsForPushTests(); - } - else { - parms = parmsIn; - } - parms.arguments.overwrite = overwrite; - - let err: Error; - let response: string; - try { - const bp = new BundlePusher(parms, localBundleDir); - response = await bp.performPush(); - } catch (e) { - err = e; - } - expect(err).toBeUndefined(); - expect(response).toContain(expectedResponse); + let parms: IHandlerParameters; + if (parmsIn === undefined) { + parms = getCommonParmsForPushTests(); + } + else { + parms = parmsIn; + } + parms.arguments.overwrite = overwrite; + + let err: Error; + let response: string; + try { + const bp = new BundlePusher(parms, localBundleDir); + response = await bp.performPush(); + } catch (e) { + err = e; + } + expect(err).toBeUndefined(); + expect(response).toContain(expectedResponse); } function getCommonParmsForPushTests(): IHandlerParameters { - let parms: IHandlerParameters; - parms = DEFAULT_PARAMTERS; - parms.arguments.cicshlq = "12345678901234567890123456789012345"; - parms.arguments.cpsmhlq = "abcde12345abcde12345abcde12345abcde"; - parms.arguments.cicsplex = "12345678"; - parms.arguments.scope = "12345678"; - parms.arguments.csdgroup = undefined; - parms.arguments.resgroup = undefined; - parms.arguments.timeout = undefined; - parms.arguments.name = "12345678"; - parms.arguments.jobcard = "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"; - parms.arguments.targetstate = "ENABLED"; - parms.arguments.targetdir = "/u/ThisDoesNotExist"; - parms.arguments.overwrite = undefined; - parms.arguments.zh = undefined; - parms.arguments.zp = undefined; - parms.arguments.zu = undefined; - parms.arguments.zpw = undefined; - parms.arguments.zru = undefined; - parms.arguments.zbp = undefined; - parms.arguments.sh = undefined; - parms.arguments.sp = undefined; - parms.arguments.su = undefined; - parms.arguments.spw = undefined; - parms.arguments.spk = undefined; - parms.arguments.skp = undefined; - parms.arguments.sht = undefined; - parms.arguments.ch = undefined; - parms.arguments.cpo = undefined; - parms.arguments.cu = undefined; - parms.arguments.cpw = undefined; - parms.arguments.cru = undefined; - parms.arguments.cpr = undefined; - return parms; + let parms: IHandlerParameters; + // eslint-disable-next-line prefer-const + parms = DEFAULT_PARAMTERS; + parms.arguments.cicshlq = "12345678901234567890123456789012345"; + parms.arguments.cpsmhlq = "abcde12345abcde12345abcde12345abcde"; + parms.arguments.cicsplex = "12345678"; + parms.arguments.scope = "12345678"; + parms.arguments.csdgroup = undefined; + parms.arguments.resgroup = undefined; + parms.arguments.timeout = undefined; + parms.arguments.name = "12345678"; + parms.arguments.jobcard = "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT"; + parms.arguments.targetstate = "ENABLED"; + parms.arguments.targetdir = "/u/ThisDoesNotExist"; + parms.arguments.overwrite = undefined; + parms.arguments.zh = undefined; + parms.arguments.zp = undefined; + parms.arguments.zu = undefined; + parms.arguments.zpw = undefined; + parms.arguments.zru = undefined; + parms.arguments.zbp = undefined; + parms.arguments.sh = undefined; + parms.arguments.sp = undefined; + parms.arguments.su = undefined; + parms.arguments.spw = undefined; + parms.arguments.spk = undefined; + parms.arguments.skp = undefined; + parms.arguments.sht = undefined; + parms.arguments.ch = undefined; + parms.arguments.cpo = undefined; + parms.arguments.cu = undefined; + parms.arguments.cpw = undefined; + parms.arguments.cru = undefined; + parms.arguments.cpr = undefined; + return parms; } diff --git a/__tests__/api/BundlePush/SubtaskWithStatus.test.ts b/__tests__/api/BundlePush/SubtaskWithStatus.test.ts index 550036d6..0dec6c21 100644 --- a/__tests__/api/BundlePush/SubtaskWithStatus.test.ts +++ b/__tests__/api/BundlePush/SubtaskWithStatus.test.ts @@ -31,41 +31,48 @@ describe("SubtaskWithStatus", () => { it("Should fail with ticks > 0", () => { expect(() => { + // eslint-disable-next-line no-magic-numbers const task = new SubtaskWithStatus(parentTask, 101); }).toThrow("Ticks must be between 0 and 100"); }); it("Should set the parent task status", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 20); subTask.statusMessage = "Message from subtask"; expect(parentTask.statusMessage).toEqual("Message from subtask"); }); it("Should set the parent task stage", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 20); subTask.stageName = TaskStage.FAILED; expect(parentTask.stageName).toEqual(TaskStage.FAILED); }); it("Should not set the parent task to completed", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 20); subTask.stageName = TaskStage.COMPLETE; expect(parentTask.stageName).toEqual(TaskStage.IN_PROGRESS); }); it("Should not set the parent task to NOT_STARTED", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 20); subTask.stageName = TaskStage.NOT_STARTED; expect(parentTask.stageName).toEqual(TaskStage.IN_PROGRESS); }); it("should set percentComplete on parent task using scaled value", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 20); subTask.percentComplete = TaskProgress.FIFTY_PERCENT; expect(parentTask.percentComplete).toEqual(TaskProgress.TEN_PERCENT); }); it("should add to percentComplete on parent task using scaled value", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); parentTask.percentComplete = 50; subTask.percentComplete = TaskProgress.FIFTY_PERCENT; @@ -73,6 +80,7 @@ describe("SubtaskWithStatus", () => { }); it("should add to percentComplete on parent task using scaled value multiple times", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); parentTask.percentComplete = TaskProgress.FIFTY_PERCENT; subTask.percentComplete = 25; @@ -82,28 +90,35 @@ describe("SubtaskWithStatus", () => { }); it("should return subtask percentage complete", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); subTask.percentComplete = 50; + // eslint-disable-next-line no-magic-numbers expect(subTask.percentComplete).toEqual(50); }); it("should allow really small increments", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); subTask.percentComplete = 50; + // eslint-disable-next-line no-magic-numbers for (let i = 0; i < 40; i++) { subTask.percentComplete += 0.25; } + // eslint-disable-next-line no-magic-numbers expect(parentTask.percentComplete).toBeCloseTo(24); }); it("should return subtask stage", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); subTask.stageName = TaskStage.IN_PROGRESS; expect(subTask.stageName).toEqual(TaskStage.IN_PROGRESS); }); it("should return subtask status message", () => { + // eslint-disable-next-line no-magic-numbers const subTask = new SubtaskWithStatus(parentTask, 40); subTask.statusMessage = "Status"; expect(subTask.statusMessage).toEqual("Status"); diff --git a/__tests__/cli/deploy/bundle/DeployBundle.handler.test.ts b/__tests__/cli/deploy/bundle/DeployBundle.handler.test.ts index fef07be1..8fa10308 100644 --- a/__tests__/cli/deploy/bundle/DeployBundle.handler.test.ts +++ b/__tests__/cli/deploy/bundle/DeployBundle.handler.test.ts @@ -25,10 +25,10 @@ const DEFAULT_PARAMETERS: IHandlerParameters = { profiles: { get: (type: string) => { if (type === "cics-deploy") { - return undefined; + return undefined; } if (type === "zosmf") { - return undefined; + return undefined; } return {}; } @@ -76,8 +76,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -100,8 +100,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -132,8 +132,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -150,8 +150,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -171,8 +171,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -192,8 +192,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -214,8 +214,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -229,8 +229,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -250,8 +250,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -271,17 +271,19 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } expectImperativeErrorWithMessage(err, "--timeout parameter is not an integer"); }); it("should complain with non-integer timeout", async () => { + // eslint-disable-next-line no-magic-numbers await testTimeoutError(1.1, "--timeout parameter is not an integer"); }); it("should complain with too large timeout", async () => { + // eslint-disable-next-line no-magic-numbers await testTimeoutError(1801, "--timeout parameter is too large"); }); it("should complain with too small timeout", async () => { @@ -298,8 +300,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -322,8 +324,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -346,8 +348,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -382,8 +384,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -393,7 +395,8 @@ describe("bundle Handler", () => { await testTargetStateDeployError("", "--targetstate parameter is empty"); }); it("should complain with invalid targetstate parameter", async () => { - await testTargetStateDeployError("Wibble", "--targetstate has invalid value. Found WIBBLE but expected one of DISABLED, ENABLED or AVAILABLE."); + await testTargetStateDeployError("Wibble", + "--targetstate has invalid value. Found WIBBLE but expected one of DISABLED, ENABLED or AVAILABLE."); }); it("should complain with invalid type for verbose parameter", async () => { @@ -404,8 +407,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -420,8 +423,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); + const handler = new DeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -430,278 +433,278 @@ describe("bundle Handler", () => { }); function setCommonParmsForNameTests(parms: IHandlerParameters) { - parms.arguments.name = undefined; - parms.arguments.bundledir = undefined; - parms.arguments["cics-deploy-profile"] = undefined; - parms.arguments.cicsplex = undefined; - parms.arguments.scope = undefined; - parms.arguments.resgroup = undefined; - parms.arguments.csdgroup = undefined; - parms.arguments.timeout = undefined; - parms.arguments.cicshlq = undefined; - parms.arguments.cpsmhlq = undefined; - parms.arguments.targetstate = undefined; - parms.arguments.jobcard = undefined; - parms.arguments.verbose = undefined; - parms.arguments.description = undefined; + parms.arguments.name = undefined; + parms.arguments.bundledir = undefined; + parms.arguments["cics-deploy-profile"] = undefined; + parms.arguments.cicsplex = undefined; + parms.arguments.scope = undefined; + parms.arguments.resgroup = undefined; + parms.arguments.csdgroup = undefined; + parms.arguments.timeout = undefined; + parms.arguments.cicshlq = undefined; + parms.arguments.cpsmhlq = undefined; + parms.arguments.targetstate = undefined; + parms.arguments.jobcard = undefined; + parms.arguments.verbose = undefined; + parms.arguments.description = undefined; } async function testNameError(name: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForNameTests(params); - params.arguments.name = name; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForNameTests(params); + params.arguments.name = name; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForBundledirTests(parms: IHandlerParameters) { - setCommonParmsForNameTests(parms); - parms.arguments.name = "WIBBLE"; + setCommonParmsForNameTests(parms); + parms.arguments.name = "WIBBLE"; } async function testBundledirError(bundledir: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForBundledirTests(params); - params.arguments.bundledir = bundledir; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForBundledirTests(params); + params.arguments.bundledir = bundledir; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForProfileTests(parms: IHandlerParameters) { - setCommonParmsForBundledirTests(parms); - parms.arguments.bundledir = "wibble"; + setCommonParmsForBundledirTests(parms); + parms.arguments.bundledir = "wibble"; } async function testProfileError(profile: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForProfileTests(params); - params.arguments["cics-deploy-profile"] = profile; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForProfileTests(params); + params.arguments["cics-deploy-profile"] = profile; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForCicsplexTests(parms: IHandlerParameters) { - setCommonParmsForProfileTests(parms); - parms.arguments.scope = "wibblE"; + setCommonParmsForProfileTests(parms); + parms.arguments.scope = "wibblE"; } async function testCicsplexError(cicsplex: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForCicsplexTests(params); - params.arguments.cicsplex = cicsplex; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForCicsplexTests(params); + params.arguments.cicsplex = cicsplex; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForScopeTests(parms: IHandlerParameters) { - setCommonParmsForProfileTests(parms); - parms.arguments["cics-deploy-profile"] = undefined; - parms.arguments.cicsplex = "Wibble"; + setCommonParmsForProfileTests(parms); + parms.arguments["cics-deploy-profile"] = undefined; + parms.arguments.cicsplex = "Wibble"; } async function testScopeError(scope: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForScopeTests(params); - params.arguments.scope = scope; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForScopeTests(params); + params.arguments.scope = scope; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForCsdgroupTests(parms: IHandlerParameters) { - setCommonParmsForScopeTests(parms); - parms.arguments.scope = "wibblE"; + setCommonParmsForScopeTests(parms); + parms.arguments.scope = "wibblE"; } async function testCsdgroupError(csdgroup: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForResgroupTests(params); - params.arguments.csdgroup = csdgroup; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForResgroupTests(params); + params.arguments.csdgroup = csdgroup; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForResgroupTests(parms: IHandlerParameters) { - setCommonParmsForCsdgroupTests(parms); + setCommonParmsForCsdgroupTests(parms); } async function testResgroupError(resgroup: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForResgroupTests(params); - params.arguments.resgroup = resgroup; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForResgroupTests(params); + params.arguments.resgroup = resgroup; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForDescriptionTests(parms: IHandlerParameters) { - setCommonParmsForResgroupTests(parms); + setCommonParmsForResgroupTests(parms); } async function testDescriptionError(description: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForDescriptionTests(params); - params.arguments.description = description; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForDescriptionTests(params); + params.arguments.description = description; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForTimeoutTests(parms: IHandlerParameters) { - setCommonParmsForResgroupTests(parms); - parms.arguments.resgroup = "wiBBle"; + setCommonParmsForResgroupTests(parms); + parms.arguments.resgroup = "wiBBle"; } async function testTimeoutError(timeout: number, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForTimeoutTests(params); - params.arguments.timeout = timeout; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, (result)); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForTimeoutTests(params); + params.arguments.timeout = timeout; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, (result)); } function setCommonParmsForCicsHLQTests(parms: IHandlerParameters) { - setCommonParmsForTimeoutTests(parms); + setCommonParmsForTimeoutTests(parms); } async function testCicsHLQError(cicshlq: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForCicsHLQTests(params); - params.arguments.cicshlq = cicshlq; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForCicsHLQTests(params); + params.arguments.cicshlq = cicshlq; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForCpsmHLQTests(parms: IHandlerParameters) { - setCommonParmsForCicsHLQTests(parms); - parms.arguments.cicshlq = "WIBB.LE"; + setCommonParmsForCicsHLQTests(parms); + parms.arguments.cicshlq = "WIBB.LE"; } async function testCpsmHLQError(cpsmhlq: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForCpsmHLQTests(params); - params.arguments.cpsmhlq = cpsmhlq; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForCpsmHLQTests(params); + params.arguments.cpsmhlq = cpsmhlq; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForJobcardTests(parms: IHandlerParameters) { - setCommonParmsForCpsmHLQTests(parms); - parms.arguments.cpsmhlq = "WI.BBLE"; - parms.arguments.targetstate = "ENABLED"; + setCommonParmsForCpsmHLQTests(parms); + parms.arguments.cpsmhlq = "WI.BBLE"; + parms.arguments.targetstate = "ENABLED"; } async function testJobcardError(jobcard: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForJobcardTests(params); - params.arguments.jobcard = jobcard; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForJobcardTests(params); + params.arguments.jobcard = jobcard; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function setCommonParmsForTargetStateTests(parms: IHandlerParameters) { - setCommonParmsForJobcardTests(parms); - parms.arguments.targetstate = undefined; + setCommonParmsForJobcardTests(parms); + parms.arguments.targetstate = undefined; } async function testTargetStateDeployError(targetstate: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForTargetStateTests(params); - params.arguments.targetstate = targetstate; - - let err: Error; - try { - const handler = new DeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expectImperativeErrorWithMessage(err, result); + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForTargetStateTests(params); + params.arguments.targetstate = targetstate; + + let err: Error; + try { + const handler = new DeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expectImperativeErrorWithMessage(err, result); } function expectImperativeErrorWithMessage(err: any, message: string) { - expect(err).toBeDefined(); - expect(err).toBeInstanceOf(ImperativeError); - expect(err.message).toContain(message); + expect(err).toBeDefined(); + expect(err).toBeInstanceOf(ImperativeError); + expect(err.message).toContain(message); } diff --git a/__tests__/cli/generate/bundle/GenerateBundle.handler.test.ts b/__tests__/cli/generate/bundle/GenerateBundle.handler.test.ts index 9a6ea11e..a61f8f60 100644 --- a/__tests__/cli/generate/bundle/GenerateBundle.handler.test.ts +++ b/__tests__/cli/generate/bundle/GenerateBundle.handler.test.ts @@ -68,16 +68,23 @@ describe("bundle Handler", () => { it("should process the current directory", async () => { DEFAULT_PARAMTERS.arguments.nosave = "true"; + // Move to the currentDirectory test folder + const startingDirectory = process.cwd(); + process.chdir("__tests__/__resources__/CurrentDirectory"); + let error; try { - const handler = new GenerateBundleHandler.default(); - // The handler should succeed - const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); - await handler.process(params); + const handler = new GenerateBundleHandler.default(); + // The handler should succeed + const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); + await handler.process(params); } catch (e) { error = e; Imperative.console.error(`Error experienced: ${e.message}`); } + // Move back to the correct starting directory + process.chdir(startingDirectory); + expect(consoleText).toContain("define : NODEJSAPP \"zowe-cli-cics-deploy-plugin\" with startscript \"lib/index.js\""); expect(consoleText).toContain("CICS Bundle generated with bundleid \"zowe-cli-cics-deploy-plugin\""); expect(error).toBeUndefined(); @@ -93,10 +100,10 @@ describe("bundle Handler", () => { let error; try { - const handler = new GenerateBundleHandler.default(); - // The handler should succeed - const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); - await handler.process(params); + const handler = new GenerateBundleHandler.default(); + // The handler should succeed + const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); + await handler.process(params); } catch (e) { error = e; Imperative.console.error(`Error experienced: ${e.message}`); @@ -113,10 +120,10 @@ describe("bundle Handler", () => { let error; try { - const handler = new GenerateBundleHandler.default(); - // The handler should succeed - const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); - await handler.process(params); + const handler = new GenerateBundleHandler.default(); + // The handler should succeed + const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); + await handler.process(params); } catch (e) { error = e; Imperative.console.error(`Error experienced: ${e.message}`); @@ -128,18 +135,18 @@ describe("bundle Handler", () => { }); it("should produce the correct messages when overwrite on", async () => { DEFAULT_PARAMTERS.arguments.nosave = "false"; - jest.spyOn(fs, "writeFileSync").mockReturnValue(true); - jest.spyOn(fs, "mkdirSync").mockReturnValue(true); + jest.spyOn(fs, "writeFileSync").mockReturnValue(); + jest.spyOn(fs, "mkdirSync").mockReturnValue(); const currentDir = process.cwd(); process.chdir("__tests__/__resources__/ExampleBundle04"); let error; try { - const handler = new GenerateBundleHandler.default(); - // The handler should succeed - const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); - await handler.process(params); + const handler = new GenerateBundleHandler.default(); + // The handler should succeed + const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); + await handler.process(params); } catch (e) { error = e; Imperative.console.error(`Error experienced: ${e.message}`); @@ -157,18 +164,18 @@ describe("bundle Handler", () => { it("should produce the correct messages when merge on", async () => { DEFAULT_PARAMTERS.arguments.nosave = "false"; DEFAULT_PARAMTERS.arguments.merge = "true"; - jest.spyOn(fs, "writeFileSync").mockReturnValue(true); - jest.spyOn(fs, "mkdirSync").mockReturnValue(true); + jest.spyOn(fs, "writeFileSync").mockReturnValue(); + jest.spyOn(fs, "mkdirSync").mockReturnValue(); const currentDir = process.cwd(); process.chdir("__tests__/__resources__/ExampleBundle05"); let error; try { - const handler = new GenerateBundleHandler.default(); - // The handler should succeed - const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); - await handler.process(params); + const handler = new GenerateBundleHandler.default(); + // The handler should succeed + const params = Object.assign({}, ...[DEFAULT_PARAMTERS]); + await handler.process(params); } catch (e) { error = e; Imperative.console.error(`Error experienced: ${e.message}`); diff --git a/__tests__/cli/push/bundle/PushBundle.handler.test.ts b/__tests__/cli/push/bundle/PushBundle.handler.test.ts index a2070ca9..a73157a1 100644 --- a/__tests__/cli/push/bundle/PushBundle.handler.test.ts +++ b/__tests__/cli/push/bundle/PushBundle.handler.test.ts @@ -25,10 +25,10 @@ const DEFAULT_PARAMETERS: IHandlerParameters = { profiles: { get: (type: string) => { if (type === "cics-deploy") { - return undefined; + return undefined; } if (type === "zosmf") { - return undefined; + return undefined; } return {}; } @@ -72,42 +72,42 @@ describe("bundle Handler", () => { }); function getCommonParms(): IHandlerParameters { - const parms = Object.assign({}, ...[DEFAULT_PARAMETERS]); - parms.arguments.name = undefined; - parms.arguments.targetdir = undefined; - parms.arguments["cics-deploy-profile"] = undefined; - parms.arguments.cicsplex = undefined; - parms.arguments.scope = undefined; - parms.arguments.resgroup = undefined; - parms.arguments.csdgroup = undefined; - parms.arguments.timeout = undefined; - parms.arguments.cicshlq = undefined; - parms.arguments.cpsmhlq = undefined; - parms.arguments.targetstate = undefined; - parms.arguments.jobcard = undefined; - parms.arguments.verbose = undefined; + const parms = Object.assign({}, ...[DEFAULT_PARAMETERS]); + parms.arguments.name = undefined; + parms.arguments.targetdir = undefined; + parms.arguments["cics-deploy-profile"] = undefined; + parms.arguments.cicsplex = undefined; + parms.arguments.scope = undefined; + parms.arguments.resgroup = undefined; + parms.arguments.csdgroup = undefined; + parms.arguments.timeout = undefined; + parms.arguments.cicshlq = undefined; + parms.arguments.cpsmhlq = undefined; + parms.arguments.targetstate = undefined; + parms.arguments.jobcard = undefined; + parms.arguments.verbose = undefined; - return parms; + return parms; } async function testError(parms: IHandlerParameters, result: string) { - const currentDir = process.cwd(); - process.chdir("__tests__/__resources__/ExampleBundle01"); + const currentDir = process.cwd(); + process.chdir("__tests__/__resources__/ExampleBundle01"); - let err: Error; - try { - const handler = new PushBundleHandler.default(); - await handler.process(parms); - } catch (e) { - err = e; - } - process.chdir(currentDir); - expectImperativeErrorWithMessage(err, result); + let err: Error; + try { + const handler = new PushBundleHandler.default(); + await handler.process(parms); + } catch (e) { + err = e; + } + process.chdir(currentDir); + expectImperativeErrorWithMessage(err, result); } function expectImperativeErrorWithMessage(err: any, message: string) { - expect(err).toBeDefined(); - expect(err).toBeInstanceOf(ImperativeError); - expect(err.message).toContain(message); + expect(err).toBeDefined(); + expect(err).toBeInstanceOf(ImperativeError); + expect(err.message).toContain(message); } diff --git a/__tests__/cli/undeploy/bundle/UndeployBundle.handler.test.ts b/__tests__/cli/undeploy/bundle/UndeployBundle.handler.test.ts index ee564c1c..51c82c56 100644 --- a/__tests__/cli/undeploy/bundle/UndeployBundle.handler.test.ts +++ b/__tests__/cli/undeploy/bundle/UndeployBundle.handler.test.ts @@ -66,8 +66,8 @@ describe("bundle Handler", () => { let err: Error; const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); try { - const handler = new UndeployBundleHandler.default(); - await handler.process(params); + const handler = new UndeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -91,8 +91,8 @@ describe("bundle Handler", () => { let err: Error; try { - const handler = new UndeployBundleHandler.default(); - await handler.process(params); + const handler = new UndeployBundleHandler.default(); + await handler.process(params); } catch (e) { err = e; } @@ -104,37 +104,38 @@ describe("bundle Handler", () => { await testTargetStateUndeployError("", "--targetstate parameter is empty"); }); it("should complain with invalid targetstate parameter UNDEPLOY", async () => { - await testTargetStateUndeployError("Wibble", "--targetstate has invalid value. Found WIBBLE but expected one of UNAVAILABLE, DISABLED or DISCARDED."); + await testTargetStateUndeployError("Wibble", + "--targetstate has invalid value. Found WIBBLE but expected one of UNAVAILABLE, DISABLED or DISCARDED."); }); }); function setCommonParmsForTargetStateTests(parms: IHandlerParameters) { - parms.arguments.name = "WIBBLE"; - parms.arguments["cics-deploy-profile"] = undefined; - parms.arguments.cicsplex = "Wibble"; - parms.arguments.scope = "wibblE"; - parms.arguments.resgroup = "wiBBle"; - parms.arguments.csdgroup = undefined; - parms.arguments.timeout = undefined; - parms.arguments.cicshlq = "WIBB.LE"; - parms.arguments.cpsmhlq = "WIBB.LE"; - parms.arguments.targetstate = undefined; - parms.arguments.jobcard = undefined; + parms.arguments.name = "WIBBLE"; + parms.arguments["cics-deploy-profile"] = undefined; + parms.arguments.cicsplex = "Wibble"; + parms.arguments.scope = "wibblE"; + parms.arguments.resgroup = "wiBBle"; + parms.arguments.csdgroup = undefined; + parms.arguments.timeout = undefined; + parms.arguments.cicshlq = "WIBB.LE"; + parms.arguments.cpsmhlq = "WIBB.LE"; + parms.arguments.targetstate = undefined; + parms.arguments.jobcard = undefined; } async function testTargetStateUndeployError(targetstate: string, result: string) { - const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); - setCommonParmsForTargetStateTests(params); - params.arguments.targetstate = targetstate; + const params = Object.assign({}, ...[DEFAULT_PARAMETERS]); + setCommonParmsForTargetStateTests(params); + params.arguments.targetstate = targetstate; - let err: Error; - try { - const handler = new UndeployBundleHandler.default(); - await handler.process(params); - } catch (e) { - err = e; - } - expect(err).toBeDefined(); - expect(err).toBeInstanceOf(ImperativeError); - expect(err.message).toContain(result); + let err: Error; + try { + const handler = new UndeployBundleHandler.default(); + await handler.process(params); + } catch (e) { + err = e; + } + expect(err).toBeDefined(); + expect(err).toBeInstanceOf(ImperativeError); + expect(err.message).toContain(result); } diff --git a/docs/pages/cdp/CLIReadme.md b/docs/pages/cdp/CLIReadme.md index 73b63a16..3a1fe83c 100644 --- a/docs/pages/cdp/CLIReadme.md +++ b/docs/pages/cdp/CLIReadme.md @@ -80,7 +80,7 @@ the target group of CICS regions\. * Specifies the job card to use with any generated DFHDPLOY JCL\. Use this parameter if you need to tailor the job card and you have not set the \-\-cics\-deploy\-profile option\. You can separate multiple lines of the - jobcard with \n\. + jobcard with \\n\. Default value: //DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT @@ -154,7 +154,7 @@ processing takes too long: * `$ zowe cics-deploy deploy bundle --name EXAMPLE --bundle-directory /u/example/bundleDir --timeout 60` * Deploy a CICS bundle to a specific target environment by -using specific zosmf & cics-deploy profiles: +using specific zosmf & cics\-deploy profiles: * `$ zowe cics-deploy deploy bundle --name EXAMPLE --bundle-directory /u/example/bundleDir --cicsplex TESTPLEX --scope SCOPE --res-group BUNDGRP --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 --zosmf-profile testplex --cics-deploy-profile devcics` @@ -188,7 +188,7 @@ required\. * `--nodejsapp` | `-n` | `--nj` | `--nja` *(string)* - * The ID of the generated CICS NODEJSAPP resource, up to 32 characters\. If no + * The ID of the generated CICS NODEJSAPP resource, up to 32 characters\. If no value is specified, a default value is created from the 'name' property in package\.json, or the bundleid option if specified\. If the value is too long it is truncated\. If it contains characters that are not supported by CICS, each @@ -225,17 +225,17 @@ required\. #### Examples * Generate a CICS bundle in the working directory, taking -information from package.json: +information from package\.json: * `$ zowe cics-deploy generate bundle` * Generate a CICS bundle in the working directory, based on -package.json but using a bundle ID of "mybundle": +package\.json but using a bundle ID of "mybundle": * `$ zowe cics-deploy generate bundle --bundle-id mybundle` * Generate a CICS bundle in the working directory in which a -package.json does not exist: +package\.json does not exist: * `$ zowe cics-deploy generate bundle --bundle-id mybundle --nodejsapp myapp --start-script server.js` @@ -309,7 +309,7 @@ Push a CICS bundle from the working directory to a target CICSplex\. * Specifies the job card to use with any generated DFHDPLOY JCL\. Use this parameter if you need to tailor the job card and you have not set the \-\-cics\-deploy\-profile option\. You can separate multiple lines of the - jobcard with \n\. + jobcard with \\n\. Default value: //DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT @@ -447,12 +447,12 @@ Push a CICS bundle from the working directory to a target CICSplex\. #### Examples * Push a CICS bundle from the working directory by using -default cics-deploy, cics, ssh and zosmf profiles: +default cics\-deploy, cics, ssh and zosmf profiles: * `$ zowe cics-deploy push bundle --name EXAMPLE --target-directory /u/example/bundles` * Push a CICS bundle from the working directory by using -specific zosmf, ssh & cics-deploy profiles: +specific zosmf, ssh & cics\-deploy profiles: * `$ zowe cics-deploy push bundle --name EXAMPLE --target-directory /u/example/bundles --zosmf-profile testplex --cics-deploy-profile devcics --ssh-profile ssh` @@ -522,7 +522,7 @@ target group of CICS regions\. * Specifies the job card to use with any generated DFHDPLOY JCL\. Use this parameter if you need to tailor the job card and you have not set the \-\-cics\-deploy\-profile option\. You can separate multiple lines of the - jobcard with \n\. + jobcard with \\n\. Default value: //DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT @@ -585,7 +585,7 @@ target group of CICS regions\. #### Examples -* Undeploy a CICS bundle by using the default cics-deploy and +* Undeploy a CICS bundle by using the default cics\-deploy and zosmf profiles: * `$ zowe cics-deploy undeploy bundle --name EXAMPLE` @@ -596,12 +596,12 @@ processing takes too long: * `$ zowe cics-deploy undeploy bundle --name EXAMPLE --timeout 60` * Undeploy a CICS bundle from a specific target environment by -using specific zosmf and cics-deploy profiles: +using specific zosmf and cics\-deploy profiles: * `$ zowe cics-deploy undeploy bundle --name EXAMPLE --cics-plex TESTPLEX --scope SCOPE --res-group BUNDGRP --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 --zosmf-profile testplex --cics-deploy-profile devcics` # profiles -Create and manage configuration profiles +Create and manage configuration profiles. ## create | cre Create new configuration profiles. ### cics-deploy-profile @@ -679,21 +679,21 @@ actions\. #### Examples -* Create a cics-deploy profile called 'example1' to connect to -a CPSM managed group of CICS regions within the TESTGRP1 scope of a cicsplex +* Create a cics\-deploy profile called 'example1' to connect +to a CPSM managed group of CICS regions within the TESTGRP1 scope of a cicsplex named PLEX1: * `$ zowe profiles create cics-deploy-profile example1 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550` -* Create a cics-deploy profile called 'example2' to connect to -the same CPSM managed group of regions, and identify a BAS resource group +* Create a cics\-deploy profile called 'example2' to connect +to the same CPSM managed group of regions, and identify a BAS resource group BUNDGRP1 in which to store resource definitions: * `$ zowe profiles create cics-deploy-profile example2 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 --res-group BUNDGRP1` -* Create a cics-deploy profile called 'example3' to connect to -the same CPSM managed group of regions, and identify the default USS directory -to which bundles should be uploaded: +* Create a cics\-deploy profile called 'example3' to connect +to the same CPSM managed group of regions, and identify the default USS +directory to which bundles should be uploaded: * `$ zowe profiles create cics-deploy-profile example3 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 --target-directory /var/cicsts/bundles` @@ -775,8 +775,8 @@ command\. By default, you will be prompted to confirm the profile removal\. * `profileName` *(string)* - * Specifies the name of the cics\-deploy profile to be deleted\. You can also load - this profile by using the name on commands that support the + * Specifies the name of the cics\-deploy profile to be deleted\. You can also + load this profile by using the name on commands that support the "\-\-cics\-deploy\-profile" option\. #### Options @@ -784,16 +784,16 @@ command\. By default, you will be prompted to confirm the profile removal\. * `--force` *(boolean)* * Force deletion of profile, and dependent profiles if specified\. No prompt will - be displayed before deletion occurs\. + be displayed before deletion occurs\. #### Examples -* Delete a cics-deploy profile named profilename: +* Delete a cics\-deploy profile named profilename: * `$ zowe profiles delete cics-deploy-profile profilename` ## list | ls -List profiles of the type +List profiles of the type . ### cics-deploy-profiles Specifies the target environment for the cics\-deploy deploy and undeploy actions\. @@ -806,16 +806,16 @@ actions\. * `--show-contents` | `--sc` *(boolean)* - * List cics\-deploy profiles and their contents\. All profile details will be + * List cics\-deploy profiles and their contents\. All profile details will be printed as part of command output\. #### Examples -* List profiles of type cics-deploy: +* List profiles of type cics\-deploy: * `$ zowe profiles list cics-deploy-profiles` -* List profiles of type cics-deploy and display their +* List profiles of type cics\-deploy and display their contents: * `$ zowe profiles list cics-deploy-profiles --sc` @@ -844,7 +844,7 @@ requirements\. #### Examples -* Set the default profile for type cics-deploy to the profile +* Set the default profile for type cics\-deploy to the profile named 'profilename': * `$ zowe profiles set-default cics-deploy-profile profilename` diff --git a/junit.xml b/junit.xml index f2fe3f23..5ecfb125 100644 --- a/junit.xml +++ b/junit.xml @@ -1,65 +1,834 @@ - - - + + + - + - + - + - + - + - + - + - + - - Error: expect(received).not.toBe(expected) // Object.is equality + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 1 +Received number of calls: 0 + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:360:25 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + + + + + + + Error: expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 1 +Received number of calls: 0 + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:401:25 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Error: expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 1 +Received number of calls: 0 + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1280:25 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + Error: expect(received).toContain(expected) // indexOf + +Expected substring: "Regions in scope '12345678' of CICSplex '12345678':" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1309:29 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + Error: expect(jest.fn()).toHaveBeenCalledTimes(expected) + +Expected number of calls: 1 +Received number of calls: 0 + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1353:25 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + Error: expect(received).toContain(expected) // indexOf + +Expected substring: "Regions in scope '12345678' of CICSplex '12345678':" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2055I DFHRL2067WDeploy ended with errors +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1399:29 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + Error: expect(jest.fn()).toHaveBeenCalledTimes(expected) -Expected: not "" - at C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:131:44 +Expected number of calls: 1 +Received number of calls: 0 + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1437:25 at Generator.next (<anonymous>) - at fulfilled (C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:16:58) - at process._tickCallback (internal/process/next_tick.js:68:7) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - + + Error: expect(received).toContain(expected) // indexOf + +Expected substring: "zowe cics get resource CICSNodejsapp --region-name 12345678 --criteria \"BUNDLE=12345678\" --cics-plex 12345678" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1474:29 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - + + Error: expect(received).toContain(expected) // indexOf + +Expected substring: "zowe cics get resource CICSNodejsapp --region-name 12345678 --criteria \"BUNDLE=12345678\" --cics-plex 12345678" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1523:29 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - + + Error: expect(received).toContain(expected) // indexOf + +Expected substring: "Regions in scope '12345678' of CICSplex '12345678':" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1579:29 + at Generator.next (<anonymous>) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - - Error: expect(received).not.toBe(expected) // Object.is equality + + Error: expect(received).toContain(expected) // indexOf -Expected: not "" - at C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:131:44 +Expected substring: "Regions in scope '12345678' of CICSplex '12345678':" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1639:29 at Generator.next (<anonymous>) - at fulfilled (C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:16:58) - at process._tickCallback (internal/process/next_tick.js:68:7) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - - Error: expect(received).not.toBe(expected) // Object.is equality + + Error: expect(received).toContain(expected) // indexOf -Expected: not "" - at C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:131:44 +Expected substring: "Regions in scope '12345678' of CICSplex '12345678':" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2012IDeploy complete +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1710:29 at Generator.next (<anonymous>) - at fulfilled (C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:16:58) - at process._tickCallback (internal/process/next_tick.js:68:7) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) - - Error: expect(received).not.toBe(expected) // Object.is equality + + Error: expect(received).not.toContain(expected) // indexOf -Expected: not "" - at C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:131:44 +Expected substring: not "An attempt to query the remote CICSplex using the cics plug-in has failed" +Received string: "Making remote bundle directory '/u/ThisDoesNotExist/12345678' +Accessing contents of remote bundle directory +Uploading bundle contents to remote directory +WARNING: No .zosattributes file found in the bundle directory, default values will be applied. +Deploying bundle '12345678' to CICS +DFHRL2055IDeploy ended with errors +Gathering scope information +Querying regions in scope over CMCI +An attempt to query the remote CICSplex using the cics plug-in has failed. +DFHDPLOY output implied the bundle failed to install. Check the output above for further information. Consider examining the JESMSGLG, MSGUSR, SYSPRINT and SYSOUT spool files of the CICS region job, or consult your CICS system programmer. +" + at /Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:1780:33 at Generator.next (<anonymous>) - at fulfilled (C:\temp\zowe\cics\zowe-cli-cics-deploy-plugin\__tests__\__system__\cli\generate\cli.generate.bundle.system.test.ts:16:58) - at process._tickCallback (internal/process/next_tick.js:68:7) + at fulfilled (/Users/adamcoulthard/Documents/git/zowe-cli-cics-deploy-plugin/__tests__/api/BundlePush/BundlePusher.test.ts:15:58) + at processTicksAndRejections (node:internal/process/task_queues:95:5) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 0753ac28..80b41df9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "clean": "rimraf lib", "watch": "tsc --pretty --watch", "prepublishOnly": "npm run build", - "lint": "tslint \"src/**/*.ts\" && tslint \"**/__tests__/**/*.ts\"", + "lint": "eslint \"src/**/*.ts\" && eslint \"**/__tests__/**/*.ts\" --ignore-pattern \"__tests__/__resources__/\"", "test": "npm run test:unit && npm run test:system", "test:system": "env-cmd __tests__/__resources__/env/system.env jest .*/__system__/.* --coverage false", "test:unit": "env-cmd __tests__/__resources__/env/unit.env jest --runInBand --detectOpenHandles --coverage --testPathIgnorePatterns \".*/__system__/.*\"", @@ -41,18 +41,26 @@ "configurationModule": "lib/imperative.js" }, "dependencies": { - "@zowe/cics-for-zowe-cli": "^3.6.1", + "@zowe/cics-for-zowe-cli": "^4.0.8", "fast-xml-parser": "^3.16.0" }, "devDependencies": { - "@zowe/cli": "^6.0.0", - "@zowe/imperative": "^4.7.3", "@types/fs-extra": "^8.0.1", - "@types/jest": "^22.2.3", + "@types/jest": "^29.5.11", "@types/node": "^12.12.24", "@types/yargs": "^13.0.4", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/eslint-plugin-tslint": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", + "@zowe/cli": "^6.0.0", + "@zowe/imperative": "^4.7.3", "clear-require": "^2.0.0", "env-cmd": "^8.0.2", + "eslint": "^8.55.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jsdoc": "^46.9.0", + "eslint-plugin-prefer-arrow": "^1.2.3", + "eslint-plugin-unicorn": "^49.0.0", "fs-extra": "^8.1.0", "gulp": "^4.0.2", "gulp-cli": "^2.2.1", @@ -60,20 +68,19 @@ "gulp-plumber": "^1.2.1", "gulp-replace": "^1.0.0", "gulp-util": "^3.0.8", - "jest": "^26.0.1", - "jest-cli": "^26.0.1", - "jest-environment-node": "^26.0.1", + "jest": "^29.7.0", + "jest-cli": "^29.7.0", + "jest-environment-node": "^29.7.0", "jest-environment-node-debug": "^2.0.0", - "jest-html-reporter": "^3.1.3", - "jest-junit": "^10.0.0", + "jest-html-reporter": "^3.10.2", + "jest-junit": "^16.0.0", "js-yaml": "^3.14.0", "mustache": "^4.0.1", "rimraf": "^3.0.2", - "ts-jest": "^26.1.0", + "ts-jest": "^29.1.1", "ts-node": "^8.10.2", - "tslint": "^6.1.2", "typedoc": "^0.17.7", - "typescript": "^3.9.5", + "typescript": "^5.3.3", "uuid": "^3.3.2" }, "peerDependencies": { @@ -84,7 +91,10 @@ "modulePathIgnorePatterns": [ "__tests__/__snapshots__/" ], - "reporters": [ "default", "jest-junit" ], + "reporters": [ + "default", + "jest-junit" + ], "transform": { ".(ts)": "ts-jest" }, diff --git a/src/api/BundleContent/AutoBundler.ts b/src/api/BundleContent/AutoBundler.ts index 7603c4d1..4b714012 100644 --- a/src/api/BundleContent/AutoBundler.ts +++ b/src/api/BundleContent/AutoBundler.ts @@ -25,23 +25,24 @@ import { Logger, IHandlerParameters } from "@zowe/imperative"; */ export class AutoBundler { - private MAX_NODEJSAPP_LEN = 32; - private bundle: Bundle; - private fs = require("fs"); - private path = require("path"); - private packageJsonFile: string; - private bundleidOverride: string; - private bundleMajorVerOverride: number; - private bundleMinorVerOverride: number; - private bundleMicroVerOverride: number; - private nodejsappOverride: string; - private startscriptOverride: string; - private portOverride: number; - private bundleDirectory: string; - private overwrite: boolean = false; - private merge: boolean = false; - - /** + // eslint-disable-next-line no-magic-numbers + private MAX_NODEJSAPP_LEN = 32; + private bundle: Bundle; + private fs = require("fs"); + private path = require("path"); + private packageJsonFile: string; + private bundleidOverride: string; + private bundleMajorVerOverride: number; + private bundleMinorVerOverride: number; + private bundleMicroVerOverride: number; + private nodejsappOverride: string; + private startscriptOverride: string; + private portOverride: number; + private bundleDirectory: string; + private overwrite: boolean = false; + private merge: boolean = false; + + /** * Constructor to perform the automatic bundle enablement. * @param {string} directory - The bundle directory. * @param {IHandlerParameters} params - The Imperative handler parameters @@ -49,201 +50,201 @@ export class AutoBundler { * @throws ImperativeError * @memberof AutoBundler */ - constructor(directory: string, params: IHandlerParameters) { + constructor(directory: string, params: IHandlerParameters) { - this.bundleDirectory = this.path.normalize(directory); - this.packageJsonFile = directory + "/package.json"; - this.validateMergeAndOverwrite(params.arguments.merge, params.arguments.overwrite); - this.bundle = new Bundle(this.bundleDirectory, this.merge, this.overwrite, params); - this.discoverArguments(params); + this.bundleDirectory = this.path.normalize(directory); + this.packageJsonFile = directory + "/package.json"; + this.validateMergeAndOverwrite(params.arguments.merge, params.arguments.overwrite); + this.bundle = new Bundle(this.bundleDirectory, this.merge, this.overwrite, params); + this.discoverArguments(params); - this.autoDetectWorkdirContent(params); - } + this.autoDetectWorkdirContent(params); + } - /** + /** * Returns the generated Bundle instance. * @throws ImperativeError * @returns {Bundle} * @memberof AutoBundler */ - public getBundle(): Bundle { - return this.bundle; - } + public getBundle(): Bundle { + return this.bundle; + } - /** + /** * Save the generated Bundle * * @throws ImperativeError * @memberof AutoBundler */ - public save() { - this.bundle.save(); - } + public save() { + this.bundle.save(); + } - private autoDetectWorkdirContent(params: IHandlerParameters) { + private autoDetectWorkdirContent(params: IHandlerParameters) { - // Look for a package.json file; if found, process the contents for a NODEJSAPP - if (this.fs.existsSync(this.packageJsonFile)) { - this.processPackageJson(params); - } - else { - // If we get here then we've not found a package.json file. it remains possible - // that sufficient command line parameters have been set to allow a NODEJSAPP - // to be created. If so, process them. - if (this.startscriptOverride !== undefined || + // Look for a package.json file; if found, process the contents for a NODEJSAPP + if (this.fs.existsSync(this.packageJsonFile)) { + this.processPackageJson(params); + } + else { + // If we get here then we've not found a package.json file. it remains possible + // that sufficient command line parameters have been set to allow a NODEJSAPP + // to be created. If so, process them. + if (this.startscriptOverride !== undefined || this.nodejsappOverride !== undefined || this.portOverride !== undefined ) { - this.bundle.addNodejsappDefinition(this.nodejsappOverride, this.startscriptOverride, this.portOverride); - try { - const msg = 'define : NODEJSAPP "' + this.nodejsappOverride + '" with startscript "' + this.startscriptOverride + '"'; - params.response.console.log(msg); - - // Also log the message for posterity - if (params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(msg); - } + this.bundle.addNodejsappDefinition(this.nodejsappOverride, this.startscriptOverride, this.portOverride); + try { + const msg = 'define : NODEJSAPP "' + this.nodejsappOverride + '" with startscript "' + this.startscriptOverride + '"'; + params.response.console.log(msg); + + // Also log the message for posterity + if (params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(msg); + } + } + catch (error) { + // logging errors can be thrown in some of the mocked tests... just ignore it. + } + } } - catch (error) { - // logging errors can be thrown in some of the mocked tests... just ignore it. - } - } } - } - private processPackageJson(params: IHandlerParameters) { + private processPackageJson(params: IHandlerParameters) { - // read the package.json file - let pj; - try { - pj = JSON.parse(this.fs.readFileSync(this.packageJsonFile, "utf8")); - } - catch (exception) - { - throw new Error("Parsing error occurred reading package.json: " + exception.message); - } + // read the package.json file + let pj; + try { + pj = JSON.parse(this.fs.readFileSync(this.packageJsonFile, "utf8")); + } + catch (exception) + { + throw new Error("Parsing error occurred reading package.json: " + exception.message); + } - // Find the name from package.json - const name = pj.name; + // Find the name from package.json + const name = pj.name; - // Set the name of the Bundle based on what was found - if (this.bundleidOverride === undefined) { - if (name === undefined) { - throw new Error("No bundleid value set"); - } - this.bundle.setId(name); - } + // Set the name of the Bundle based on what was found + if (this.bundleidOverride === undefined) { + if (name === undefined) { + throw new Error("No bundleid value set"); + } + this.bundle.setId(name); + } - // Recover the mangled variant of the name (it may be different from what we started with) - const bundleName = this.bundle.getId(); + // Recover the mangled variant of the name (it may be different from what we started with) + const bundleName = this.bundle.getId(); - // Set the Bundle version to 1.0.0 - if (this.bundleMajorVerOverride === undefined) { - this.bundle.setVersion(1, 0, 0); - } + // Set the Bundle version to 1.0.0 + if (this.bundleMajorVerOverride === undefined) { + this.bundle.setVersion(1, 0, 0); + } - // truncate the Bundle name to find a suitable NODEJSAPP resource name - let njappname = this.nodejsappOverride; - if (njappname === undefined) { - njappname = bundleName; - } - njappname = njappname.substring(0, this.MAX_NODEJSAPP_LEN); - - // get the start script - let ss = this.startscriptOverride; - let fullSS = ss; - if (ss === undefined) { - if (pj.scripts !== undefined) { - ss = pj.scripts.start; - } - if (ss !== undefined) { - // Remove the first word from the value (which will be the node command) - ss = ss.substr(ss.indexOf(" ") + 1).trim(); - fullSS = this.bundleDirectory + "/" + ss; - } - // If there's no start script, try the main script instead - else { - ss = pj.main; - - if (ss !== undefined) { - fullSS = this.bundleDirectory + "/" + pj.main; - } - } - } + // truncate the Bundle name to find a suitable NODEJSAPP resource name + let njappname = this.nodejsappOverride; + if (njappname === undefined) { + njappname = bundleName; + } + njappname = njappname.substring(0, this.MAX_NODEJSAPP_LEN); + + // get the start script + let ss = this.startscriptOverride; + let fullSS = ss; + if (ss === undefined) { + if (pj.scripts !== undefined) { + ss = pj.scripts.start; + } + if (ss !== undefined) { + // Remove the first word from the value (which will be the node command) + ss = ss.substr(ss.indexOf(" ") + 1).trim(); + fullSS = this.bundleDirectory + "/" + ss; + } + // If there's no start script, try the main script instead + else { + ss = pj.main; + + if (ss !== undefined) { + fullSS = this.bundleDirectory + "/" + pj.main; + } + } + } - // Add the NODEJSAPP to the Bundle - this.bundle.addNodejsappDefinition(njappname, fullSS, this.portOverride); - try { - // Construct an info message to report that the NODEJSAPP has been created - const msg = ' define : NODEJSAPP "' + njappname + '" with startscript "' + ss + '"'; + // Add the NODEJSAPP to the Bundle + this.bundle.addNodejsappDefinition(njappname, fullSS, this.portOverride); + try { + // Construct an info message to report that the NODEJSAPP has been created + const msg = ' define : NODEJSAPP "' + njappname + '" with startscript "' + ss + '"'; - // log the message to the console for the uesr - params.response.console.log(msg); + // log the message to the console for the uesr + params.response.console.log(msg); - // Also log the message for posterity - if (params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(msg); - } - } - catch (error) { - // logging errors can be thrown in some of the mocked tests... just ignore it. + // Also log the message for posterity + if (params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(msg); + } + } + catch (error) { + // logging errors can be thrown in some of the mocked tests... just ignore it. + } } - } - private discoverArguments(params: IHandlerParameters) { + private discoverArguments(params: IHandlerParameters) { + + const args = params.arguments; - const args = params.arguments; + if (args.bundleid !== undefined) { + this.validateBundleId(args.bundleid); + } + if (args.bundleversion !== undefined) { + this.validateBundleVer(args.bundleversion); + } + if (args.nodejsapp !== undefined) { + this.validateNodejsapp(args.nodejsapp); + } + if (args.startscript !== undefined) { + this.validateStartscript(args.startscript); + } + if (args.port !== undefined) { + this.validatePort(args.port); + } + } - if (args.bundleid !== undefined) { - this.validateBundleId(args.bundleid); + private validateBundleId(value: string) { + this.bundleidOverride = value; + this.bundle.setId(this.bundleidOverride); } - if (args.bundleversion !== undefined) { - this.validateBundleVer(args.bundleversion); + + private validateBundleVer(value: string) { + const splitString = value.split("."); + this.bundleMajorVerOverride = parseInt(splitString[0], 10); + this.bundleMinorVerOverride = parseInt(splitString[1], 10); + this.bundleMicroVerOverride = parseInt(splitString[2], 10); + this.bundle.setVersion(this.bundleMajorVerOverride, + this.bundleMinorVerOverride, + this.bundleMicroVerOverride); } - if (args.nodejsapp !== undefined) { - this.validateNodejsapp(args.nodejsapp); + + private validateNodejsapp(value: string) { + this.nodejsappOverride = value; } - if (args.startscript !== undefined) { - this.validateStartscript(args.startscript); + + private validateStartscript(value: string) { + this.startscriptOverride = value; } - if (args.port !== undefined) { - this.validatePort(args.port); + + private validatePort(value: string) { + this.portOverride = parseInt(value, 10); } - } - - private validateBundleId(value: string) { - this.bundleidOverride = value; - this.bundle.setId(this.bundleidOverride); - } - - private validateBundleVer(value: string) { - const splitString = value.split("."); - this.bundleMajorVerOverride = parseInt(splitString[0], 10); - this.bundleMinorVerOverride = parseInt(splitString[1], 10); - this.bundleMicroVerOverride = parseInt(splitString[2], 10); - this.bundle.setVersion(this.bundleMajorVerOverride, - this.bundleMinorVerOverride, - this.bundleMicroVerOverride); - } - - private validateNodejsapp(value: string) { - this.nodejsappOverride = value; - } - - private validateStartscript(value: string) { - this.startscriptOverride = value; - } - - private validatePort(value: string) { - this.portOverride = parseInt(value, 10); - } - - private validateMergeAndOverwrite(merge: boolean, overwrite: boolean) { - if (merge === true && overwrite !== true) { - throw new Error("--merge requires the use of --overwrite"); + + private validateMergeAndOverwrite(merge: boolean, overwrite: boolean) { + if (merge === true && overwrite !== true) { + throw new Error("--merge requires the use of --overwrite"); + } + this.merge = merge; + this.overwrite = overwrite; } - this.merge = merge; - this.overwrite = overwrite; - } } diff --git a/src/api/BundleContent/Bundle.ts b/src/api/BundleContent/Bundle.ts index 1f6a07c0..58e36296 100644 --- a/src/api/BundleContent/Bundle.ts +++ b/src/api/BundleContent/Bundle.ts @@ -24,13 +24,13 @@ import { IHandlerParameters } from "@zowe/imperative"; */ export class Bundle { - /** + /** * Get a template version of the .zosattributes file * @returns {string} * @memberof Bundle */ - public static getTemplateZosAttributesFile(): string { - return `#z/OS File Attributes Document + public static getTemplateZosAttributesFile(): string { + return `#z/OS File Attributes Document #----------------------------- # This document specfies the encodings for the files within # the project in a form that is compatible with the @@ -53,22 +53,22 @@ node_modules - # Convert CICS Node.js profiles to EBCDIC *.profile ISO8859-1 IBM-1047`; - } - - private path = require("path"); - private fs = require("fs"); - private manifest: Manifest; - private definedParts: BundlePart[] = []; - private bundleDirectory: string; - private merge: boolean; - private overwrite: boolean; - private preparedToSave: boolean = false; - private zosAttribsNeeded: boolean = false; - private zosAttribsAlreadyExists: boolean = false; - private zosAttribsFile: string; - private params: IHandlerParameters; - - /** + } + + private path = require("path"); + private fs = require("fs"); + private manifest: Manifest; + private definedParts: BundlePart[] = []; + private bundleDirectory: string; + private merge: boolean; + private overwrite: boolean; + private preparedToSave: boolean = false; + private zosAttribsNeeded: boolean = false; + private zosAttribsAlreadyExists: boolean = false; + private zosAttribsFile: string; + private params: IHandlerParameters; + + /** * Constructor for creating a Bundle. * @static * @param {string} directory - The bundle directory. @@ -78,97 +78,97 @@ node_modules - * @throws ImperativeError * @memberof Bundle */ - constructor(directory: string, merge: boolean, overwrite: boolean, params?: IHandlerParameters) { - this.merge = merge; - this.overwrite = overwrite; - this.params = params; - this.bundleDirectory = this.path.normalize(directory); - this.manifest = new Manifest(this.bundleDirectory, this.merge, this.overwrite, params); - this.preparedToSave = false; - this.zosAttribsFile = this.path.join(this.bundleDirectory, ".zosattributes"); - this.zosAttribsNeeded = true; - } - - /** + constructor(directory: string, merge: boolean, overwrite: boolean, params?: IHandlerParameters) { + this.merge = merge; + this.overwrite = overwrite; + this.params = params; + this.bundleDirectory = this.path.normalize(directory); + this.manifest = new Manifest(this.bundleDirectory, this.merge, this.overwrite, params); + this.preparedToSave = false; + this.zosAttribsFile = this.path.join(this.bundleDirectory, ".zosattributes"); + this.zosAttribsNeeded = true; + } + + /** * Validates that a Bundle appears to be valid on the file-system * @returns {string} * @throws ImperativeError * @memberof Bundle */ - public validate() { + public validate() { - // check that the manifest file exists. We could perform a more rigorous - // validation of the contents of the Bundle, but this simple check is - // sufficient to ensure the bundle is broadly valid on the file-system. - // Errors will be thrown to report problems. - this.manifest.validate(); - } + // check that the manifest file exists. We could perform a more rigorous + // validation of the contents of the Bundle, but this simple check is + // sufficient to ensure the bundle is broadly valid on the file-system. + // Errors will be thrown to report problems. + this.manifest.validate(); + } - /** + /** * Determines whether the Bundle contains the named resource * @param {string} resource - The resource to query * @returns {boolean} * @throws ImperativeError * @memberof Bundle */ - public contains(resource: string): boolean { - const fullyQualifiedResourceName = this.path.join(this.bundleDirectory, resource); - const relative = BundlePart.getRelativeFileReference(fullyQualifiedResourceName, this.bundleDirectory); - if (relative === undefined) { - // The file isn't within the Bundle directory - return false; - } + public contains(resource: string): boolean { + const fullyQualifiedResourceName = this.path.join(this.bundleDirectory, resource); + const relative = BundlePart.getRelativeFileReference(fullyQualifiedResourceName, this.bundleDirectory); + if (relative === undefined) { + // The file isn't within the Bundle directory + return false; + } - const fullLocation = this.path.join(this.bundleDirectory, relative); - if (!this.fs.existsSync(fullLocation)) { - return false; - } + const fullLocation = this.path.join(this.bundleDirectory, relative); + if (!this.fs.existsSync(fullLocation)) { + return false; + } - return true; - } + return true; + } - /** + /** * Determines whether the Bundle contains any resources of the specified type * @param {string} resource - The resource to query * @returns {boolean} * @throws ImperativeError * @memberof Bundle */ - public containsDefinitionsOfType(resourceType: string): boolean { - return this.manifest.containsDefinitionsOfType(resourceType); - } + public containsDefinitionsOfType(resourceType: string): boolean { + return this.manifest.containsDefinitionsOfType(resourceType); + } - /** + /** * Returns the Bundle's identity (id) value. * @returns {string} * @throws ImperativeError * @memberof Bundle */ - public getId(): string { - return this.manifest.getBundleId(); - } + public getId(): string { + return this.manifest.getBundleId(); + } - /** + /** * Set the Bundle's identity (id) value. * @param {string} id - The identity value for the Bundle. * @throws ImperativeError * @memberof Bundle */ - public setId(id: string) { - this.manifest.setBundleId(id); - } + public setId(id: string) { + this.manifest.setBundleId(id); + } - /** + /** * Returns the Bundle's version value. * @returns {string} * @throws ImperativeError * @memberof Bundle */ - public getVersion(): string { - return this.manifest.getBundleVersion(); - } + public getVersion(): string { + return this.manifest.getBundleVersion(); + } - /** + /** * Set the Bundle's version number. * @param {number} majorVersion - The major version number. * @param {number} minorVersion - The minor version number. @@ -176,33 +176,33 @@ node_modules - * @throws ImperativeError * @memberof Bundle */ - public setVersion(majorVersion: number, minorVersion: number, microVersion: number) { - this.manifest.setBundleVersion(majorVersion, minorVersion, microVersion); - } + public setVersion(majorVersion: number, minorVersion: number, microVersion: number) { + this.manifest.setBundleVersion(majorVersion, minorVersion, microVersion); + } - /** + /** * Returns the Manifest contents as a JSON Object. * * @returns {object} * @throws ImperativeError * @memberof Bundle */ - public getManifest(): object { - return this.manifest.getJson(); - } + public getManifest(): object { + return this.manifest.getJson(); + } - /** + /** * Returns the Manifest contents as an XML string. * * @returns {string} * @throws ImperativeError * @memberof Bundle */ - public getManifestXML(): string { - return this.manifest.getXML(); - } + public getManifestXML(): string { + return this.manifest.getXML(); + } - /** + /** * Add a resource definition to the Bundle. If a part of the same name and type * already exists then it is replaced with the new part data. * @@ -210,15 +210,15 @@ node_modules - * @throws ImperativeError * @memberof Bundle */ - public addDefinition(partData: IBundlePartDataType) { + public addDefinition(partData: IBundlePartDataType) { // Create a BundlePart - this.preparedToSave = false; - const bp = new BundlePart(this.bundleDirectory, partData, true, undefined, this.overwrite, this.params); - this.definedParts.push(bp); - this.manifest.addDefinition(bp); - } + this.preparedToSave = false; + const bp = new BundlePart(this.bundleDirectory, partData, true, undefined, this.overwrite, this.params); + this.definedParts.push(bp); + this.manifest.addDefinition(bp); + } - /** + /** * Add a NODEJSAPP resource definition to the Bundle. If a NODEJSAPP of the same name * already exists then it is replaced with the new part data. * @@ -228,15 +228,15 @@ node_modules - * @throws ImperativeError * @memberof Bundle */ - public addNodejsappDefinition(name: string, startscript: string, port: number) { - this.preparedToSave = false; - const nj = new NodejsappBundlePart(this.bundleDirectory, name, startscript, port, this.overwrite, this.params); - this.manifest.addDefinition(nj); - this.definedParts.push(nj); - this.zosAttribsNeeded = true; - } - - /** + public addNodejsappDefinition(name: string, startscript: string, port: number) { + this.preparedToSave = false; + const nj = new NodejsappBundlePart(this.bundleDirectory, name, startscript, port, this.overwrite, this.params); + this.manifest.addDefinition(nj); + this.definedParts.push(nj); + this.zosAttribsNeeded = true; + } + + /** * Each bundle part is prompted to ensure that it is in a fit state to be saved. * This might involve ensuring that file system permissions are suitable and that * existing files wont be overwritten. The goal is that errors can be detected @@ -247,76 +247,76 @@ node_modules - * @throws ImperativeError * @memberof Bundle */ - public prepareForSave() { + public prepareForSave() { // prepare the manifest, this will check write access to the target directory // (amongst other things). - this.manifest.prepareForSave(); + this.manifest.prepareForSave(); - // prepare each bundle part in turn - this.definedParts.forEach( (value) => { - value.prepareForSave(); - }); + // prepare each bundle part in turn + this.definedParts.forEach( (value) => { + value.prepareForSave(); + }); - // prepare the .zosattributes file (which can be useful for transferring a - // bundle to zFS). - this.prepareZosAttribs(); + // prepare the .zosattributes file (which can be useful for transferring a + // bundle to zFS). + this.prepareZosAttribs(); - this.preparedToSave = true; - } + this.preparedToSave = true; + } - /** + /** * Save the current Bundle. Any changes that have been made will be persisted. * * @throws ImperativeError * @memberof Bundle */ - public save() { + public save() { // Prepare the resources to be saved, without actually saving them. This should // cause most common errors to be detected before we start persisting anything. // If an error does occur mid-save then we have a better chance of avoiding a // broken Bundle. - if (this.preparedToSave === false) { - this.prepareForSave(); - } - - // save the parts - this.definedParts.forEach( (value) => { - value.save(); - }); + if (this.preparedToSave === false) { + this.prepareForSave(); + } - // save the zosattributes - this.writeZosAttribs(); + // save the parts + this.definedParts.forEach( (value) => { + value.save(); + }); - // save the manifest - this.manifest.save(); - } + // save the zosattributes + this.writeZosAttribs(); - private prepareZosAttribs() { - if (this.zosAttribsNeeded) { - this.zosAttribsAlreadyExists = BundlePart.alreadyExists(this.zosAttribsFile, this.overwrite); + // save the manifest + this.manifest.save(); } - } - private writeZosAttribs() { - if (!this.zosAttribsNeeded) { - return; + private prepareZosAttribs() { + if (this.zosAttribsNeeded) { + this.zosAttribsAlreadyExists = BundlePart.alreadyExists(this.zosAttribsFile, this.overwrite); + } } - const contents = Bundle.getTemplateZosAttributesFile(); + private writeZosAttribs() { + if (!this.zosAttribsNeeded) { + return; + } - // Write the zosattributes file - try { - if (this.params !== undefined) { - let action = " create"; - if (this.zosAttribsAlreadyExists) { - action = " overwrite"; + const contents = Bundle.getTemplateZosAttributesFile(); + + // Write the zosattributes file + try { + if (this.params !== undefined) { + let action = " create"; + if (this.zosAttribsAlreadyExists) { + action = " overwrite"; + } + this.params.response.console.log(action + " : " + this.path.relative(this.bundleDirectory, this.zosAttribsFile)); + } + this.fs.writeFileSync(this.zosAttribsFile, contents, "utf8"); + } + catch (err) { + throw new Error("An error occurred attempting to write .zosattributes file '" + this.zosAttribsFile + "': " + err.message); } - this.params.response.console.log(action + " : " + this.path.relative(this.bundleDirectory, this.zosAttribsFile)); - } - this.fs.writeFileSync(this.zosAttribsFile, contents, "utf8"); - } - catch (err) { - throw new Error("An error occurred attempting to write .zosattributes file '" + this.zosAttribsFile + "': " + err.message); } - } } diff --git a/src/api/BundleContent/BundlePart.ts b/src/api/BundleContent/BundlePart.ts index 55ec9fde..b0d7cfb9 100644 --- a/src/api/BundleContent/BundlePart.ts +++ b/src/api/BundleContent/BundlePart.ts @@ -21,9 +21,9 @@ import { IHandlerParameters } from "@zowe/imperative"; * @interface IBundlePartDataType */ export interface IBundlePartDataType { - name: string; - type: string; - path: string; + name: string; + type: string; + path: string; } /** @@ -35,7 +35,7 @@ export interface IBundlePartDataType { export class BundlePart { - /** + /** * Perform checks to determine whether it is likely that a file can be written. * * @param {string} filename - The file to check @@ -43,29 +43,29 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - public static alreadyExists(filename: string, overwrite: boolean): boolean { + public static alreadyExists(filename: string, overwrite: boolean): boolean { // Does the file already exist? - if (BundlePart.fs.existsSync(filename)) { - // Are we allowed to replace it? - if (overwrite === false) { - throw new Error("File " + filename + " already exists. Specify --overwrite to replace it."); - } - - // Do we have write permission to it? - try { - BundlePart.fs.accessSync(filename, BundlePart.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + filename); - } - - return true; + if (BundlePart.fs.existsSync(filename)) { + // Are we allowed to replace it? + if (overwrite === false) { + throw new Error("File " + filename + " already exists. Specify --overwrite to replace it."); + } + + // Do we have write permission to it? + try { + BundlePart.fs.accessSync(filename, BundlePart.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + filename); + } + + return true; + } + + return false; } - return false; - } - - /** + /** * Determine whether a file reference is local to the Bundle. Returns a normalised * reference, or null if the reference is invalid. * @@ -75,48 +75,48 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - public static getRelativeFileReference(filename: string, bundledir: string): string { + public static getRelativeFileReference(filename: string, bundledir: string): string { // normalise it (to get rid of dots) - let file = BundlePart.path.normalize(filename); + let file = BundlePart.path.normalize(filename); - // find the location of the target relative to the current directory - file = this.path.relative(bundledir, file); + // find the location of the target relative to the current directory + file = this.path.relative(bundledir, file); - // the target file is not within the current directory tree throw an error - if (file.indexOf("..") === 0) { - return undefined; + // the target file is not within the current directory tree throw an error + if (file.indexOf("..") === 0) { + return undefined; + } + return file; } - return file; - } - protected static fs = require("fs"); - protected static path = require("path"); + protected static fs = require("fs"); + protected static path = require("path"); - /** + /** * Function for mangaling a name into something valid for CICS * * @throws ImperativeError * @memberof BundlePart */ - protected static mangleName(text: string, maxLength: number): string { + protected static mangleName(text: string, maxLength: number): string { - // replace underscore with hyphen - let mangledText = text.replace(/_/g, "-"); + // replace underscore with hyphen + let mangledText = text.replace(/_/g, "-"); - // Convert all unsupported characters to X - mangledText = mangledText.replace(/[^0-9,^A-Z,^a-z\-]/g, "X"); + // Convert all unsupported characters to X + mangledText = mangledText.replace(/[^0-9,^A-Z,^a-z\-]/g, "X"); - // Now truncate the string - return mangledText.substring(0, maxLength); - } + // Now truncate the string + return mangledText.substring(0, maxLength); + } - protected bundleDirectory: string; - protected overwrite: boolean; - private partData: IBundlePartDataType; - private simpleType = "BundlePart"; - private params: IHandlerParameters; + protected bundleDirectory: string; + protected overwrite: boolean; + private partData: IBundlePartDataType; + private simpleType = "BundlePart"; + private params: IHandlerParameters; - /** + /** * Constructor for creating a BundlePart. * @param {string} directory - The bundle directory. * @param {IBundlePartDataType} partDataLocal - The metadata for the BundlePart. @@ -127,34 +127,34 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - constructor(directory: string, partDataLocal: IBundlePartDataType, validatePath: boolean, - abbrevType: string, overwrite: boolean, params?: IHandlerParameters) { - if (abbrevType !== undefined) { - this.simpleType = abbrevType; - } - this.partData = partDataLocal; - this.overwrite = overwrite; - this.params = params; - this.bundleDirectory = BundlePart.path.normalize(directory); - this.validateName(); - this.validateType(); - if (validatePath) { - this.validatePath(); + constructor(directory: string, partDataLocal: IBundlePartDataType, validatePath: boolean, + abbrevType: string, overwrite: boolean, params?: IHandlerParameters) { + if (abbrevType !== undefined) { + this.simpleType = abbrevType; + } + this.partData = partDataLocal; + this.overwrite = overwrite; + this.params = params; + this.bundleDirectory = BundlePart.path.normalize(directory); + this.validateName(); + this.validateType(); + if (validatePath) { + this.validatePath(); + } } - } - /** + /** * Returns the BundlePart's manifest data. * * @returns {IBundlePartDataType} * @throws ImperativeError * @memberof BundlePart */ - public getPartData(): IBundlePartDataType { - return this.partData; - } + public getPartData(): IBundlePartDataType { + return this.partData; + } - /** + /** * Perform whatever validation can be done in advance of attempting to save the * BundlePart, thereby reducing the possibility of a failure after some of the * bundle's parts have already been persisted to the file system. @@ -162,21 +162,21 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - public prepareForSave() { + public prepareForSave() { // no-op, sub-classes may override this - } + } - /** + /** * Save the current BundlePart. Any changes that have been made will be persisted. * * @throws ImperativeError * @memberof BundlePart */ - public save() { + public save() { // no-op, sub-classes may override this - } + } - /** + /** * Resolves a file reference to ensure that it exists and is located within * the working directory. Returns the normalized file reference. * @@ -185,29 +185,29 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - protected normalizeAndValidateFileReference(filename: string): string { + protected normalizeAndValidateFileReference(filename: string): string { - // normalise it (to get rid of dots) - let file = BundlePart.getRelativeFileReference(filename, this.bundleDirectory); + // normalise it (to get rid of dots) + let file = BundlePart.getRelativeFileReference(filename, this.bundleDirectory); - // the target file is not within the current directory tree throw an error - if (file === undefined) { - throw new Error(this.simpleType + ' "' + this.partData.name + '" references a file outside of the Bundle directory: "' + filename + '".'); - } + // the target file is not within the current directory tree throw an error + if (file === undefined) { + throw new Error(this.simpleType + ' "' + this.partData.name + '" references a file outside of the Bundle directory: "' + filename + '".'); + } - // Check that the target file exists - const fullLocation = this.bundleDirectory + "/" + file; - if (!BundlePart.fs.existsSync(fullLocation)) { - throw new Error(this.simpleType + ' "' + this.partData.name + '" references a file that does not exist: "' + fullLocation + '".'); - } + // Check that the target file exists + const fullLocation = this.bundleDirectory + "/" + file; + if (!BundlePart.fs.existsSync(fullLocation)) { + throw new Error(this.simpleType + ' "' + this.partData.name + '" references a file that does not exist: "' + fullLocation + '".'); + } - // change any Windows style file delimiters to Unix style - file = file.replace(new RegExp("\\\\", "g"), "/"); + // change any Windows style file delimiters to Unix style + file = file.replace(new RegExp("\\\\", "g"), "/"); - return file; - } + return file; + } - /** + /** * Function to log the modification or creation of a file * * @param {string} file - the name of the file to log @@ -215,28 +215,28 @@ export class BundlePart { * @throws ImperativeError * @memberof BundlePart */ - protected logCreation(file: string, action: string) { - if (this.params !== undefined) { - this.params.response.console.log(action + " : " + BundlePart.path.relative(this.bundleDirectory, file)); + protected logCreation(file: string, action: string) { + if (this.params !== undefined) { + this.params.response.console.log(action + " : " + BundlePart.path.relative(this.bundleDirectory, file)); + } } - } - private validateName() { - if (this.partData.name === undefined) { - throw new Error(this.simpleType + " name is not set."); + private validateName() { + if (this.partData.name === undefined) { + throw new Error(this.simpleType + " name is not set."); + } } - } - private validateType() { - if (this.partData.type === undefined) { - throw new Error(this.simpleType + ' type is not set for part "' + this.partData.name + '"'); + private validateType() { + if (this.partData.type === undefined) { + throw new Error(this.simpleType + ' type is not set for part "' + this.partData.name + '"'); + } } - } - private validatePath() { - if (this.partData.path === undefined) { - throw new Error(this.simpleType + ' path is not set for part "' + this.partData.name + '"'); + private validatePath() { + if (this.partData.path === undefined) { + throw new Error(this.simpleType + ' path is not set for part "' + this.partData.name + '"'); + } + this.partData.path = this.normalizeAndValidateFileReference(this.partData.path); } - this.partData.path = this.normalizeAndValidateFileReference(this.partData.path); - } } diff --git a/src/api/BundleContent/Manifest.ts b/src/api/BundleContent/Manifest.ts index 3a193722..9e548785 100644 --- a/src/api/BundleContent/Manifest.ts +++ b/src/api/BundleContent/Manifest.ts @@ -25,7 +25,7 @@ const serialiser = new parser.j2xParser({ignoreAttributes: false, attributeNameP * @interface IManifestType */ interface IManifestType { - manifest: IManifestContents; + manifest: IManifestContents; } /** * Interface to represent the manifest data contents for CICS Bundle. @@ -34,14 +34,14 @@ interface IManifestType { * @interface IManifestContents */ interface IManifestContents { - id?: string; - xmlns?: string; - bundleVersion?: number; - bundleRelease?: number; - bundleMajorVer?: number; - bundleMinorVer?: number; - bundleMicroVer?: number; - define?: IBundlePartDataType[]; + id?: string; + xmlns?: string; + bundleVersion?: number; + bundleRelease?: number; + bundleMajorVer?: number; + bundleMinorVer?: number; + bundleMicroVer?: number; + define?: IBundlePartDataType[]; } /** @@ -52,21 +52,22 @@ interface IManifestContents { */ export class Manifest { - private MAX_BUNDLEID_LEN = 64; - private fs = require("fs"); - private path = require("path"); - private manifestAsJson: IManifestType = undefined; - private bundleDirectory: string; - private metainfDir: string; - private manifestFile: string; - private manifestExists: boolean = false; - private merge: boolean; - private overwrite: boolean; - private params: IHandlerParameters; - private manifestAction = " create"; - - - /** + // eslint-disable-next-line no-magic-numbers + private MAX_BUNDLEID_LEN = 64; + private fs = require("fs"); + private path = require("path"); + private manifestAsJson: IManifestType = undefined; + private bundleDirectory: string; + private metainfDir: string; + private manifestFile: string; + private manifestExists: boolean = false; + private merge: boolean; + private overwrite: boolean; + private params: IHandlerParameters; + private manifestAction = " create"; + + + /** * Constructor for creating a Manifest. * * @static @@ -77,40 +78,40 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - constructor(directory: string, merge: boolean, overwrite: boolean, params?: IHandlerParameters) { - this.merge = merge; - this.overwrite = overwrite; - this.bundleDirectory = this.path.normalize(directory); - this.metainfDir = this.bundleDirectory + "/META-INF"; - this.manifestFile = this.metainfDir + "/cics.xml"; - this.params = params; - - // If 'merge' is set then attempt to read any existing manifest that may - // already exist. Subsequent changes will be merged with the existing - // content. - if (this.merge === true) { - try { - this.readManifest(); - } catch (ex) { - // Something went wrong. If it's an ENOENT response then there was - // no manifest to read, so that can be ignored, otherwise propagate - // the exception back to the caller. - if (ex.code !== "ENOENT") { - throw ex; - } - } - } - - // If we've not read an existing manifest, create a new one - if (this.manifestAsJson === undefined) { - this.manifestAsJson = { manifest: + constructor(directory: string, merge: boolean, overwrite: boolean, params?: IHandlerParameters) { + this.merge = merge; + this.overwrite = overwrite; + this.bundleDirectory = this.path.normalize(directory); + this.metainfDir = this.bundleDirectory + "/META-INF"; + this.manifestFile = this.metainfDir + "/cics.xml"; + this.params = params; + + // If 'merge' is set then attempt to read any existing manifest that may + // already exist. Subsequent changes will be merged with the existing + // content. + if (this.merge === true) { + try { + this.readManifest(); + } catch (ex) { + // Something went wrong. If it's an ENOENT response then there was + // no manifest to read, so that can be ignored, otherwise propagate + // the exception back to the caller. + if (ex.code !== "ENOENT") { + throw ex; + } + } + } + + // If we've not read an existing manifest, create a new one + if (this.manifestAsJson === undefined) { + this.manifestAsJson = { manifest: { xmlns: "http://www.ibm.com/xmlns/prod/cics/bundle", bundleVersion: 1, bundleRelease: 0 } }; - } - } + } + } - /** + /** * Perform whatever validation can be done in advance of attempting to save the * manifest, thereby reducing the possibility of a failure after some of the * bundle parts have already been persisted to the file system. @@ -118,81 +119,81 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - public prepareForSave() { + public prepareForSave() { // Does the meta-inf directory already exist? - if (!this.fs.existsSync(this.metainfDir)) { - // we'll have to create it during the save, do we have write permission? - try { - this.fs.accessSync(this.bundleDirectory, this.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + this.bundleDirectory); - } - - return; - } - - // Do we have write permission to the META-INF dir? - try { - this.fs.accessSync(this.metainfDir, this.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + this.metainfDir); - } - - // Does a manifest file already exist? - if (this.fs.existsSync(this.manifestFile)) { - if (this.overwrite === false) { - throw new Error("A bundle manifest file already exists. Specify --overwrite to replace it, or --merge to merge changes into it."); - } - if (this.merge) { - this.manifestAction = " merge"; - } - else { - this.manifestAction = " overwrite"; - } - - // Do we have write permission to the manifest? - try { - this.fs.accessSync(this.manifestFile, this.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + this.manifestFile); - } + if (!this.fs.existsSync(this.metainfDir)) { + // we'll have to create it during the save, do we have write permission? + try { + this.fs.accessSync(this.bundleDirectory, this.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + this.bundleDirectory); + } + + return; + } + + // Do we have write permission to the META-INF dir? + try { + this.fs.accessSync(this.metainfDir, this.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + this.metainfDir); + } + + // Does a manifest file already exist? + if (this.fs.existsSync(this.manifestFile)) { + if (this.overwrite === false) { + throw new Error("A bundle manifest file already exists. Specify --overwrite to replace it, or --merge to merge changes into it."); + } + if (this.merge) { + this.manifestAction = " merge"; + } + else { + this.manifestAction = " overwrite"; + } + + // Do we have write permission to the manifest? + try { + this.fs.accessSync(this.manifestFile, this.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + this.manifestFile); + } + } } - } - /** + /** * Save the Manifest file. * * @throws ImperativeError * @memberof Manifest */ - public save() { - // Create the META-INF directory if it doesn't already exist - if (!this.fs.existsSync(this.metainfDir)) { - try { - this.logCreation(this.metainfDir); - this.fs.mkdirSync(this.metainfDir); - } - catch (err) { - throw new Error("An error occurred attempting to create '" + this.metainfDir + "': " + err.message); - } - } - - // Write the cics.xml manifest - try { - this.logCreation(this.manifestFile, this.manifestAction); - this.fs.writeFileSync(this.manifestFile, this.getXML(), "utf8"); - } - catch (err) { - throw new Error("An error occurred attempting to write manifest file '" + this.manifestFile + "': " + err.message); - } - - this.manifestExists = true; - } - - /** + public save() { + // Create the META-INF directory if it doesn't already exist + if (!this.fs.existsSync(this.metainfDir)) { + try { + this.logCreation(this.metainfDir); + this.fs.mkdirSync(this.metainfDir); + } + catch (err) { + throw new Error("An error occurred attempting to create '" + this.metainfDir + "': " + err.message); + } + } + + // Write the cics.xml manifest + try { + this.logCreation(this.manifestFile, this.manifestAction); + this.fs.writeFileSync(this.manifestFile, this.getXML(), "utf8"); + } + catch (err) { + throw new Error("An error occurred attempting to write manifest file '" + this.manifestFile + "': " + err.message); + } + + this.manifestExists = true; + } + + /** * Validates that a manifest file exists. If the manifest has not yet been saved then it is * invalid. * @@ -200,83 +201,83 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - public validate() { - if (!this.manifestExists) { - throw new Error("No bundle manifest file found: " + this.manifestFile); + public validate() { + if (!this.manifestExists) { + throw new Error("No bundle manifest file found: " + this.manifestFile); + } } - } - /** + /** * Returns the Manifest contents as a JSON Object. * * @returns {object} * @throws ImperativeError * @memberof Manifest */ - public getJson(): object { - return this.manifestAsJson; - } + public getJson(): object { + return this.manifestAsJson; + } - /** + /** * Returns the Manifest contents as XML text. * * @returns {string} * @throws ImperativeError * @memberof Manifest */ - public getXML(): string { - return serialiser.parse(this.manifestAsJson) + "\n"; - } + public getXML(): string { + return serialiser.parse(this.manifestAsJson) + "\n"; + } - /** + /** * Returns the Bundle's identity (id) value. * * @returns {string} * @throws ImperativeError * @memberof Manifest */ - public getBundleId(): string { - return this.manifestAsJson.manifest.id; - } + public getBundleId(): string { + return this.manifestAsJson.manifest.id; + } - /** + /** * Set the Bundle's identity (id) value. * @param {string} id - The identiry value for the Bundle. * @throws ImperativeError * @memberof Manifest */ - public setBundleId(id: string) { - if (id === undefined) { - throw new Error("BundleId not set."); + public setBundleId(id: string) { + if (id === undefined) { + throw new Error("BundleId not set."); + } + const mangledId = this.mangle(id, this.MAX_BUNDLEID_LEN); + this.manifestAsJson.manifest.id = mangledId; } - const mangledId = this.mangle(id, this.MAX_BUNDLEID_LEN); - this.manifestAsJson.manifest.id = mangledId; - } - /** + /** * Returns the Bundle's version number. * * @returns {string} * @throws ImperativeError * @memberof Manifest */ - public getBundleVersion(): string { - if (this.manifestAsJson.manifest.bundleMajorVer === undefined) { - this.manifestAsJson.manifest.bundleMajorVer = 1; - } - if (this.manifestAsJson.manifest.bundleMinorVer === undefined) { - this.manifestAsJson.manifest.bundleMinorVer = 0; - } - if (this.manifestAsJson.manifest.bundleMicroVer === undefined) { - this.manifestAsJson.manifest.bundleMicroVer = 0; - } - - return this.manifestAsJson.manifest.bundleMajorVer + "." + + public getBundleVersion(): string { + if (this.manifestAsJson.manifest.bundleMajorVer === undefined) { + this.manifestAsJson.manifest.bundleMajorVer = 1; + } + if (this.manifestAsJson.manifest.bundleMinorVer === undefined) { + this.manifestAsJson.manifest.bundleMinorVer = 0; + } + if (this.manifestAsJson.manifest.bundleMicroVer === undefined) { + this.manifestAsJson.manifest.bundleMicroVer = 0; + } + + return this.manifestAsJson.manifest.bundleMajorVer + "." + this.manifestAsJson.manifest.bundleMinorVer + "." + this.manifestAsJson.manifest.bundleMicroVer; - } + } - /** + /** * Set the Bundle's version number. * @param {number} majorVersion - The major version number. * @param {number} minorVersion - The minor version number. @@ -284,30 +285,30 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - public setBundleVersion(majorVersion: number, minorVersion: number, microVersion: number) { - if (Number.isInteger(majorVersion) && majorVersion > 0) { - this.manifestAsJson.manifest.bundleMajorVer = majorVersion; - } - else { - throw new Error("Invalid Bundle major version specified: " + majorVersion + "."); + public setBundleVersion(majorVersion: number, minorVersion: number, microVersion: number) { + if (Number.isInteger(majorVersion) && majorVersion > 0) { + this.manifestAsJson.manifest.bundleMajorVer = majorVersion; + } + else { + throw new Error("Invalid Bundle major version specified: " + majorVersion + "."); + } + + if (Number.isInteger(minorVersion) && minorVersion >= 0) { + this.manifestAsJson.manifest.bundleMinorVer = minorVersion; + } + else { + throw new Error("Invalid Bundle minor version specified: " + minorVersion + "."); + } + + if (Number.isInteger(microVersion) && microVersion >= 0) { + this.manifestAsJson.manifest.bundleMicroVer = microVersion; + } + else { + throw new Error("Invalid Bundle micro version specified: " + microVersion + "."); + } } - if (Number.isInteger(minorVersion) && minorVersion >= 0) { - this.manifestAsJson.manifest.bundleMinorVer = minorVersion; - } - else { - throw new Error("Invalid Bundle minor version specified: " + minorVersion + "."); - } - - if (Number.isInteger(microVersion) && microVersion >= 0) { - this.manifestAsJson.manifest.bundleMicroVer = microVersion; - } - else { - throw new Error("Invalid Bundle micro version specified: " + microVersion + "."); - } - } - - /** + /** * Add a resource definition to the Manifest. If a part of the same name and type * already exists then it is replaced with the new part data. * @@ -315,32 +316,32 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - public addDefinition(bundlePart: BundlePart) { + public addDefinition(bundlePart: BundlePart) { - const definition = bundlePart.getPartData(); + const definition = bundlePart.getPartData(); - // Ensure that the definitions array is usable - this.prepareDefinitionsArray(); + // Ensure that the definitions array is usable + this.prepareDefinitionsArray(); - // Search the array for a definition with the same name and - // type as the one we're trying to add, if found then update - // it with the new path. - let i: number; - for (i = 0; i < this.manifestAsJson.manifest.define.length; i++) { - const candidate = this.manifestAsJson.manifest.define[i]; - if (candidate.name === definition.name && + // Search the array for a definition with the same name and + // type as the one we're trying to add, if found then update + // it with the new path. + let i: number; + for (i = 0; i < this.manifestAsJson.manifest.define.length; i++) { + const candidate = this.manifestAsJson.manifest.define[i]; + if (candidate.name === definition.name && candidate.type === definition.type) { - candidate.path = definition.path; - return; - } + candidate.path = definition.path; + return; + } + } + + // If we've not replaced an existing item in the list, add + // the new item to the end. + this.manifestAsJson.manifest.define.push(definition); } - // If we've not replaced an existing item in the list, add - // the new item to the end. - this.manifestAsJson.manifest.define.push(definition); - } - - /** + /** * Does the bundle contain any resource definitions of the * specified type? * @@ -348,87 +349,87 @@ export class Manifest { * @throws ImperativeError * @memberof Manifest */ - public containsDefinitionsOfType(resourceType: string): boolean { - - // Ensure that the definitions array is usable - this.prepareDefinitionsArray(); - - // Search the array for a definition with the nominated type - let i: number; - for (i = 0; i < this.manifestAsJson.manifest.define.length; i++) { - const candidate = this.manifestAsJson.manifest.define[i]; - if (candidate.type === resourceType) { - return true; - } - } - - return false; - } + public containsDefinitionsOfType(resourceType: string): boolean { + // Ensure that the definitions array is usable + this.prepareDefinitionsArray(); - private prepareDefinitionsArray() { - // Create the array of definitions if it doesn't already exist - if (this.manifestAsJson.manifest.define === undefined) { - this.manifestAsJson.manifest.define = []; - } + // Search the array for a definition with the nominated type + let i: number; + for (i = 0; i < this.manifestAsJson.manifest.define.length; i++) { + const candidate = this.manifestAsJson.manifest.define[i]; + if (candidate.type === resourceType) { + return true; + } + } - // If what already exists is an object (as may happen when appending - // to an existing XML manifest with only one entry) convert it to an array; - if (Array.isArray(this.manifestAsJson.manifest.define) === false) { - const obj = this.manifestAsJson.manifest.define as any; - this.manifestAsJson.manifest.define = []; - this.manifestAsJson.manifest.define.push(obj as IBundlePartDataType); + return false; } - } - // Read an existing manifest file into an object - private readManifest() { - // read the manifest from the file system - const xmltext = this.fs.readFileSync(this.manifestFile, "utf8"); - try { - // Reading the file worked, so convert the contents into a JSON Object - this.manifestAsJson = parser.parse(xmltext, {ignoreAttributes: false, attributeNamePrefix: "", trimValues: true}); - } - catch (exception) - { - throw new Error("Parsing error occurred reading a CICS manifest file: " + exception.message); - } - - // Validate that the manifest we've read is usable. - if (this.manifestAsJson.manifest === undefined) { - throw new Error("Existing CICS Manifest file found with unparsable content: " + JSON.stringify(this.manifestAsJson)); + private prepareDefinitionsArray() { + // Create the array of definitions if it doesn't already exist + if (this.manifestAsJson.manifest.define === undefined) { + this.manifestAsJson.manifest.define = []; + } + + // If what already exists is an object (as may happen when appending + // to an existing XML manifest with only one entry) convert it to an array; + if (Array.isArray(this.manifestAsJson.manifest.define) === false) { + const obj = this.manifestAsJson.manifest.define as any; + this.manifestAsJson.manifest.define = []; + this.manifestAsJson.manifest.define.push(obj as IBundlePartDataType); + } } - // Now check the namespace - if (this.manifestAsJson.manifest.xmlns !== "http://www.ibm.com/xmlns/prod/cics/bundle") { - throw new Error("Existing CICS Manifest file found with unexpected namespace: " + this.manifestAsJson.manifest.xmlns + " ."); + // Read an existing manifest file into an object + private readManifest() { + // read the manifest from the file system + const xmltext = this.fs.readFileSync(this.manifestFile, "utf8"); + + try { + // Reading the file worked, so convert the contents into a JSON Object + this.manifestAsJson = parser.parse(xmltext, {ignoreAttributes: false, attributeNamePrefix: "", trimValues: true}); + } + catch (exception) + { + throw new Error("Parsing error occurred reading a CICS manifest file: " + exception.message); + } + + // Validate that the manifest we've read is usable. + if (this.manifestAsJson.manifest === undefined) { + throw new Error("Existing CICS Manifest file found with unparsable content: " + JSON.stringify(this.manifestAsJson)); + } + + // Now check the namespace + if (this.manifestAsJson.manifest.xmlns !== "http://www.ibm.com/xmlns/prod/cics/bundle") { + throw new Error("Existing CICS Manifest file found with unexpected namespace: " + this.manifestAsJson.manifest.xmlns + " ."); + } + + this.manifestExists = true; } - this.manifestExists = true; - } - - // Function for mangaling a string for inclusion in the manifest - private mangle(text: string, maxLength: number): string { + // Function for mangaling a string for inclusion in the manifest + private mangle(text: string, maxLength: number): string { - // replace underscore with hyphen - const text2 = text.replace(/_/g, "-"); + // replace underscore with hyphen + const text2 = text.replace(/_/g, "-"); - // Convert all unsupported characters to X - const text3 = text2.replace(/[^0-9,^A-Z,^a-z\-]/g, "X"); + // Convert all unsupported characters to X + const text3 = text2.replace(/[^0-9,^A-Z,^a-z\-]/g, "X"); - // Now truncate the string - const text4 = text3.substring(0, maxLength); + // Now truncate the string + const text4 = text3.substring(0, maxLength); - return text4; - } - - private logCreation(file: string, action?: string) { - if (action === undefined) { - action = " create"; + return text4; } - if (this.params !== undefined) { - this.params.response.console.log(action + " : " + this.path.relative(this.bundleDirectory, file)); + + private logCreation(file: string, action?: string) { + if (action === undefined) { + action = " create"; + } + if (this.params !== undefined) { + this.params.response.console.log(action + " : " + this.path.relative(this.bundleDirectory, file)); + } } - } } diff --git a/src/api/BundleContent/NodejsappBundlePart.ts b/src/api/BundleContent/NodejsappBundlePart.ts index f260b866..b2de97c0 100644 --- a/src/api/BundleContent/NodejsappBundlePart.ts +++ b/src/api/BundleContent/NodejsappBundlePart.ts @@ -25,7 +25,7 @@ const serialiser = new parser.j2xParser({ignoreAttributes: false, attributeNameP * @interface INodejsappType */ interface INodejsappType { - nodejsapp: INodejsappContents; + nodejsapp: INodejsappContents; } /** @@ -35,11 +35,11 @@ interface INodejsappType { * @interface INodejsappContents */ interface INodejsappContents { - name: string; - xmlns: string; - startscript: string; - profile: string; - lerunopts: string; + name: string; + xmlns: string; + startscript: string; + profile: string; + lerunopts: string; } @@ -51,18 +51,20 @@ interface INodejsappContents { */ export class NodejsappBundlePart extends BundlePart { - private static MAX_NODEJSAPP_LEN = 32; - private static MAX_PORT = 65535; - private nodejsappsDir: string; - private nodejsappFile: string; - private nodejsappProfile: string; - private nodejsappProfileLocal: string; - private partXML: INodejsappType; - private profile: string; - private profileAlreadyExists: boolean; - private partXMLAlreadyExists: boolean; - - /** + // eslint-disable-next-line no-magic-numbers + private static MAX_NODEJSAPP_LEN = 32; + // eslint-disable-next-line no-magic-numbers + private static MAX_PORT = 65535; + private nodejsappsDir: string; + private nodejsappFile: string; + private nodejsappProfile: string; + private nodejsappProfileLocal: string; + private partXML: INodejsappType; + private profile: string; + private profileAlreadyExists: boolean; + private partXMLAlreadyExists: boolean; + + /** * Constructor for creating a NodejsappBundlePart. * * @param {string} directory - The bundle directory. @@ -75,81 +77,81 @@ export class NodejsappBundlePart extends BundlePart { * @throws ImperativeError * @memberof NodejsappBundlePart */ - constructor(directory: string, name: string, startscript: string, port: number, overwrite: boolean, params?: IHandlerParameters) { - const partData = { name: "", - type: "http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP", - path: "" }; + constructor(directory: string, name: string, startscript: string, port: number, overwrite: boolean, params?: IHandlerParameters) { + const partData = { name: "", + type: "http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP", + path: "" }; - // Check that a name is set - if (name === undefined) { - throw new Error("NODEJSAPP name is not set."); - } + // Check that a name is set + if (name === undefined) { + throw new Error("NODEJSAPP name is not set."); + } - // Validate the name - partData.name = BundlePart.mangleName(name, NodejsappBundlePart.MAX_NODEJSAPP_LEN); + // Validate the name + partData.name = BundlePart.mangleName(name, NodejsappBundlePart.MAX_NODEJSAPP_LEN); - // Check that a startscript is set - if (startscript === undefined) { - throw new Error('No startscript value set for NODEJSAPP "' + name + '"'); - } + // Check that a startscript is set + if (startscript === undefined) { + throw new Error('No startscript value set for NODEJSAPP "' + name + '"'); + } - partData.path = "nodejsapps/" + partData.name + ".nodejsapp"; - super(directory, partData, false, "NODEJSAPP", overwrite, params); + partData.path = "nodejsapps/" + partData.name + ".nodejsapp"; + super(directory, partData, false, "NODEJSAPP", overwrite, params); - // Now validate the port - this.validatePort(port); + // Now validate the port + this.validatePort(port); - this.nodejsappsDir = this.bundleDirectory + "/nodejsapps"; - this.nodejsappFile = this.nodejsappsDir + "/" + partData.name + ".nodejsapp"; - this.nodejsappProfile = this.nodejsappsDir + "/" + partData.name + ".profile"; - this.nodejsappProfileLocal = "nodejsapps/" + partData.name + ".profile"; - this.overwrite = overwrite; - this.bundleDirectory = directory; - this.profileAlreadyExists = false; - this.partXMLAlreadyExists = false; + this.nodejsappsDir = this.bundleDirectory + "/nodejsapps"; + this.nodejsappFile = this.nodejsappsDir + "/" + partData.name + ".nodejsapp"; + this.nodejsappProfile = this.nodejsappsDir + "/" + partData.name + ".profile"; + this.nodejsappProfileLocal = "nodejsapps/" + partData.name + ".profile"; + this.overwrite = overwrite; + this.bundleDirectory = directory; + this.profileAlreadyExists = false; + this.partXMLAlreadyExists = false; - // Validate that the startscript resolves to something within the current directory - startscript = this.normalizeAndValidateFileReference(startscript); + // Validate that the startscript resolves to something within the current directory + startscript = this.normalizeAndValidateFileReference(startscript); - this.createNodejsappXML(startscript); - this.createNodejsappProfile(port); - } + this.createNodejsappXML(startscript); + this.createNodejsappProfile(port); + } - /** + /** * Get the NODEJSAPP BundlePart. * * @returns {INodejsappType} * @throws ImperativeError * @memberof NodejsappBundlePart */ - public getPart(): INodejsappType { - return this.partXML; - } + public getPart(): INodejsappType { + return this.partXML; + } - /** + /** * Get the NODEJSAPP BundlePart XML. * * @returns {string} * @throws ImperativeError * @memberof NodejsappBundlePart */ - public getPartXML(): string { - return serialiser.parse(this.partXML) + "\n"; - } + public getPartXML(): string { + return serialiser.parse(this.partXML) + "\n"; + } - /** + /** * Get the NODEJSAPP Profile text. * * @returns {string} * @throws ImperativeError * @memberof NodejsappBundlePart */ - public getProfile(): string { - return this.profile; - } + public getProfile(): string { + return this.profile; + } - /** + /** * Perform whatever validation can be done in advance of attempting to save the * Nodejsapp, thereby reducing the possibility of a failure after some of the * bundle parts have already been persisted to the file system. @@ -157,113 +159,113 @@ export class NodejsappBundlePart extends BundlePart { * @throws ImperativeError * @memberof Manifest */ - public prepareForSave() { + public prepareForSave() { // Does the nodejsapp directory already exist? - if (!BundlePart.fs.existsSync(this.nodejsappsDir)) { - - // We'll have to create it during the save, do we have write permission? - try { - BundlePart.fs.accessSync(this.bundleDirectory, BundlePart.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + this.bundleDirectory); - } - return; - } - // Do we have write permission to the nodejsapp dir? - try { - BundlePart.fs.accessSync(this.nodejsappsDir, BundlePart.fs.constants.W_OK); - } - catch (err) { - throw new Error("cics-deploy requires write permission to: " + this.nodejsappsDir); + if (!BundlePart.fs.existsSync(this.nodejsappsDir)) { + + // We'll have to create it during the save, do we have write permission? + try { + BundlePart.fs.accessSync(this.bundleDirectory, BundlePart.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + this.bundleDirectory); + } + return; + } + // Do we have write permission to the nodejsapp dir? + try { + BundlePart.fs.accessSync(this.nodejsappsDir, BundlePart.fs.constants.W_OK); + } + catch (err) { + throw new Error("cics-deploy requires write permission to: " + this.nodejsappsDir); + } + + // Does the .nodejsapp appear to be saveable? + this.partXMLAlreadyExists = BundlePart.alreadyExists(this.nodejsappFile, this.overwrite); + + // Does the .profile appear to be saveable? + this.profileAlreadyExists = BundlePart.alreadyExists(this.nodejsappProfile, this.overwrite); } - // Does the .nodejsapp appear to be saveable? - this.partXMLAlreadyExists = BundlePart.alreadyExists(this.nodejsappFile, this.overwrite); - - // Does the .profile appear to be saveable? - this.profileAlreadyExists = BundlePart.alreadyExists(this.nodejsappProfile, this.overwrite); - } - - /** + /** * Save the NODEJSAPP BundlePart. Any changes that have been made will be persisted. * * @throws ImperativeError * @memberof NodejsappBundlePart */ - public save() { + public save() { // Does the nodejsapps directory exist? If not, create it. - if (!BundlePart.fs.existsSync(this.nodejsappsDir)) { - try { - this.logCreation(this.nodejsappsDir, " create"); - BundlePart.fs.mkdirSync(this.nodejsappsDir); - } - catch (err) { - throw new Error("An error occurred attempting to create '" + this.nodejsappsDir + "': " + err.message); - } + if (!BundlePart.fs.existsSync(this.nodejsappsDir)) { + try { + this.logCreation(this.nodejsappsDir, " create"); + BundlePart.fs.mkdirSync(this.nodejsappsDir); + } + catch (err) { + throw new Error("An error occurred attempting to create '" + this.nodejsappsDir + "': " + err.message); + } + } + + // Write the .nodejsapp file + try { + let action = " create"; + if (this.partXMLAlreadyExists) { + action = " overwrite"; + } + this.logCreation(this.nodejsappFile, action); + BundlePart.fs.writeFileSync(this.nodejsappFile, this.getPartXML(), "utf8"); + } + catch (err) { + throw new Error("An error occurred attempting to write nodejsapp file '" + this.nodejsappFile + "': " + err.message); + } + + // Write the .profile file + try { + let action = " create"; + if (this.partXMLAlreadyExists) { + action = " overwrite"; + } + this.logCreation(this.nodejsappProfile, action); + BundlePart.fs.writeFileSync(this.nodejsappProfile, this.getProfile(), "utf8"); + } + catch (err) { + throw new Error("An error occurred attempting to write profile file '" + this.nodejsappProfile + "': " + err.message); + } } - // Write the .nodejsapp file - try { - let action = " create"; - if (this.partXMLAlreadyExists) { - action = " overwrite"; - } - this.logCreation(this.nodejsappFile, action); - BundlePart.fs.writeFileSync(this.nodejsappFile, this.getPartXML(), "utf8"); - } - catch (err) { - throw new Error("An error occurred attempting to write nodejsapp file '" + this.nodejsappFile + "': " + err.message); - } - - // Write the .profile file - try { - let action = " create"; - if (this.partXMLAlreadyExists) { - action = " overwrite"; - } - this.logCreation(this.nodejsappProfile, action); - BundlePart.fs.writeFileSync(this.nodejsappProfile, this.getProfile(), "utf8"); - } - catch (err) { - throw new Error("An error occurred attempting to write profile file '" + this.nodejsappProfile + "': " + err.message); - } - } - - private createNodejsappXML(startscript: string) { - this.partXML = { nodejsapp: + private createNodejsappXML(startscript: string) { + this.partXML = { nodejsapp: { - xmlns: "http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP", - name: "", - startscript: "", - profile: "", - lerunopts: "DFHSJNRO" + xmlns: "http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP", + name: "", + startscript: "", + profile: "", + lerunopts: "DFHSJNRO" } - }; - this.partXML.nodejsapp.profile = this.nodejsappProfileLocal; - this.partXML.nodejsapp.name = this.getPartData().name; - this.partXML.nodejsapp.startscript = startscript; - } - - private createNodejsappProfile(port: number) { - const os = require("os"); - this.profile = TemplateNodejsappProfile.profile; - - if (port !== undefined) { - this.profile = this.profile + "PORT=" + port.toString() + os.EOL; + }; + this.partXML.nodejsapp.profile = this.nodejsappProfileLocal; + this.partXML.nodejsapp.name = this.getPartData().name; + this.partXML.nodejsapp.startscript = startscript; } - } - // if the port is set, it must be a valid number - private validatePort(port: number) { - if (port === undefined) { - return; - } - if (!Number.isInteger(port)) { - throw new Error("Supplied Port is not an integer: " + port); + private createNodejsappProfile(port: number) { + const os = require("os"); + this.profile = TemplateNodejsappProfile.profile; + + if (port !== undefined) { + this.profile = this.profile + "PORT=" + port.toString() + os.EOL; + } } - if (port < 1 || port > NodejsappBundlePart.MAX_PORT) { - throw new Error("Supplied Port is outside the range of 1-65535: " + port); + + // if the port is set, it must be a valid number + private validatePort(port: number) { + if (port === undefined) { + return; + } + if (!Number.isInteger(port)) { + throw new Error("Supplied Port is not an integer: " + port); + } + if (port < 1 || port > NodejsappBundlePart.MAX_PORT) { + throw new Error("Supplied Port is outside the range of 1-65535: " + port); + } } - } } diff --git a/src/api/BundleContent/TemplateNodejsappProfile.ts b/src/api/BundleContent/TemplateNodejsappProfile.ts index e45f10c1..b68b550a 100644 --- a/src/api/BundleContent/TemplateNodejsappProfile.ts +++ b/src/api/BundleContent/TemplateNodejsappProfile.ts @@ -12,7 +12,7 @@ "use strict"; export class TemplateNodejsappProfile { - public static profile: string = "" + + public static profile: string = "" + "#######################################################################\n" + "# Node.js application profile: basic_nodejsapp.profile #\n" + "# #\n" + diff --git a/src/api/BundleDeploy/BundleDeployer.ts b/src/api/BundleDeploy/BundleDeployer.ts index 41013f27..c1dbf2c6 100644 --- a/src/api/BundleDeploy/BundleDeployer.ts +++ b/src/api/BundleDeploy/BundleDeployer.ts @@ -12,7 +12,7 @@ "use strict"; import { IHandlerParameters, Logger, ImperativeError, AbstractSession, ITaskWithStatus, - TaskStage , TaskProgress} from "@zowe/imperative"; + TaskStage , TaskProgress} from "@zowe/imperative"; import { ZosmfSession, SubmitJobs, List } from "@zowe/cli"; import { ParmValidator } from "./ParmValidator"; import * as path from "path"; @@ -26,170 +26,173 @@ import { ZosmfConfig } from "../BundlePush/ZosmfConfig"; */ export class BundleDeployer { - private params: IHandlerParameters; - private PROGRESS_BAR_INTERVAL = 375; // milliseconds - private PROGRESS_BAR_INCREMENT = 0.25; // percent - private PROGRESS_BAR_MAX = 67; // percent - private parmsValidated: boolean = false; - private hlqsValidated: boolean = false; - private jobId: string; - private progressBar: ITaskWithStatus; - private useResponseProgressBar = true; - private jobOutput: string = ""; - - /** + private params: IHandlerParameters; + // eslint-disable-next-line no-magic-numbers + private PROGRESS_BAR_INTERVAL = 375; // milliseconds + // eslint-disable-next-line no-magic-numbers + private PROGRESS_BAR_INCREMENT = 0.25; // percent + // eslint-disable-next-line no-magic-numbers + private PROGRESS_BAR_MAX = 67; // percent + private parmsValidated: boolean = false; + private hlqsValidated: boolean = false; + private jobId: string; + private progressBar: ITaskWithStatus; + private useResponseProgressBar = true; + private jobOutput: string = ""; + + /** * Constructor for a BundleDeployer. * @param {IHandlerParameters} params - The Imperative handler parameters * @throws ImperativeError * @memberof BundleDeployer */ - constructor(params: IHandlerParameters) { - this.params = params; - this.progressBar = { percentComplete: 0, - stageName: TaskStage.NOT_STARTED, - statusMessage: ""}; - } - - /** + constructor(params: IHandlerParameters) { + this.params = params; + this.progressBar = { percentComplete: 0, + stageName: TaskStage.NOT_STARTED, + statusMessage: ""}; + } + + /** * Deploy a CICS Bundle * @param {AbstractSession} session - An optional zOSMF session * @returns {Promise} * @throws ImperativeError * @memberof BundleDeployer */ - public async deployBundle(session?: AbstractSession, task?: ITaskWithStatus): Promise { + public async deployBundle(session?: AbstractSession, task?: ITaskWithStatus): Promise { - // Validate that the parms are valid for Deploy - this.validateDeployParms(); + // Validate that the parms are valid for Deploy + this.validateDeployParms(); - // Create a zosMF session - if (session === undefined) { - session = await this.createZosMFSession(); - } + // Create a zosMF session + if (session === undefined) { + session = await this.createZosMFSession(); + } - // Check that the CICS dataset value looks valid and can be viewed - await this.checkHLQDatasets(session); + // Check that the CICS dataset value looks valid and can be viewed + await this.checkHLQDatasets(session); - // Generate some DFHDPLOY JCL - const jcl = this.getDeployJCL(); + // Generate some DFHDPLOY JCL + const jcl = this.getDeployJCL(); - // Submit it - return this.submitJCL(jcl, "DEPLOY", session, task); - } + // Submit it + return this.submitJCL(jcl, "DEPLOY", session, task); + } - /** + /** * Undeploy a CICS Bundle * @param {AbstractSession} session - An optional zOSMF session * @returns {Promise} * @throws ImperativeError * @memberof BundleDeployer */ - public async undeployBundle(session?: AbstractSession, task?: ITaskWithStatus): Promise { + public async undeployBundle(session?: AbstractSession, task?: ITaskWithStatus): Promise { - // Validate that the parms are valid for Undeploy - this.validateUndeployParms(); + // Validate that the parms are valid for Undeploy + this.validateUndeployParms(); - // Create a zosMF session - if (session === undefined) { - session = await this.createZosMFSession(); - } + // Create a zosMF session + if (session === undefined) { + session = await this.createZosMFSession(); + } - // Check that the CICS dataset value looks valid and can be viewed - await this.checkHLQDatasets(session); + // Check that the CICS dataset value looks valid and can be viewed + await this.checkHLQDatasets(session); - // Generate some DFHDPLOY JCL - const jcl = this.getUndeployJCL(); + // Generate some DFHDPLOY JCL + const jcl = this.getUndeployJCL(); - // Submit it - return this.submitJCL(jcl, "UNDEPLOY", session, task); - } + // Submit it + return this.submitJCL(jcl, "UNDEPLOY", session, task); + } - /** + /** * Validate the input parameters are suitable for the DEPLOY action * @returns {Promise} * @throws ImperativeError * @memberof BundleDeployer */ - public validateDeployParms() { - if (this.parmsValidated === false) { - ParmValidator.validateDeploy(this.params); - this.parmsValidated = true; + public validateDeployParms() { + if (this.parmsValidated === false) { + ParmValidator.validateDeploy(this.params); + this.parmsValidated = true; + } } - } - /** + /** * Validate the input parameters are suitable for the UNDEPLOY action * @returns {Promise} * @throws ImperativeError * @memberof BundleDeployer */ - public validateUndeployParms() { - if (this.parmsValidated === false) { - ParmValidator.validateUndeploy(this.params); - this.parmsValidated = true; + public validateUndeployParms() { + if (this.parmsValidated === false) { + ParmValidator.validateUndeploy(this.params); + this.parmsValidated = true; + } } - } - /** + /** * Retrieves the output from the most recently completed DFHDPLOY JCL job. * @returns {string} * @throws ImperativeError * @memberof BundleDeployer */ - public getJobOutput() { - return this.jobOutput; - } - - private wrapLongLineForJCL(lineOfText: string): string { - const MAX_LINE_LEN = 71; - - let tempVal = lineOfText; - let returnVal = ""; - while (tempVal.length > MAX_LINE_LEN) { - returnVal = returnVal + tempVal.substring(0, MAX_LINE_LEN) + "\n"; - tempVal = " " + tempVal.substring(MAX_LINE_LEN); + public getJobOutput() { + return this.jobOutput; } - returnVal = returnVal + tempVal; - return returnVal; - } - /** + private wrapLongLineForJCL(lineOfText: string): string { + const MAX_LINE_LEN = 71; + + let tempVal = lineOfText; + let returnVal = ""; + while (tempVal.length > MAX_LINE_LEN) { + returnVal = returnVal + tempVal.substring(0, MAX_LINE_LEN) + "\n"; + tempVal = " " + tempVal.substring(MAX_LINE_LEN); + } + returnVal = returnVal + tempVal; + return returnVal; + } + + /** * Construct the DFHDPLOY DEPLOY BUNDLE JCL. * @returns {string} * @throws ImperativeError * @memberof BundleDeployer */ - private getDeployJCL(): string { + private getDeployJCL(): string { // Get rid of any extra slashes which may be needed on git-bash to avoid path munging - const bundledir = path.posix.normalize(this.params.arguments.bundledir); + const bundledir = path.posix.normalize(this.params.arguments.bundledir); - let jcl = this.generateCommonJCLHeader() + + let jcl = this.generateCommonJCLHeader() + this.wrapLongLineForJCL("DEPLOY BUNDLE(" + this.params.arguments.name + ")\n") + this.wrapLongLineForJCL(" BUNDLEDIR(" + bundledir + ")\n"); - if (this.params.arguments.description !== undefined) { - jcl += this.wrapLongLineForJCL(" DESCRIPTION(" + this.params.arguments.description + ")\n"); - } - jcl += this.generateCommonJCLFooter(); + if (this.params.arguments.description !== undefined) { + jcl += this.wrapLongLineForJCL(" DESCRIPTION(" + this.params.arguments.description + ")\n"); + } + jcl += this.generateCommonJCLFooter(); - return jcl; - } + return jcl; + } - /** + /** * Construct the DFHDPLOY UNDEPLOY BUNDLE JCL. * @returns {string} * @throws ImperativeError * @memberof BundleDeployer */ - private getUndeployJCL(): string { - const jcl = this.generateCommonJCLHeader() + + private getUndeployJCL(): string { + const jcl = this.generateCommonJCLHeader() + this.wrapLongLineForJCL("UNDEPLOY BUNDLE(" + this.params.arguments.name + ")\n") + this.generateCommonJCLFooter(); - return jcl; - } + return jcl; + } - private generateCommonJCLHeader(): string { - const jcl = this.params.arguments.jobcard + "\n" + + private generateCommonJCLHeader(): string { + const jcl = this.params.arguments.jobcard + "\n" + "//DFHDPLOY EXEC PGM=DFHDPLOY,REGION=100M\n" + "//STEPLIB DD DISP=SHR,DSN=" + this.params.arguments.cicshlq + ".SDFHLOAD\n" + "// DD DISP=SHR,DSN=" + this.params.arguments.cpsmhlq + ".SEYUAUTH\n" + @@ -199,237 +202,237 @@ export class BundleDeployer { this.wrapLongLineForJCL("SET CICSPLEX(" + this.params.arguments.cicsplex + ");\n") + this.wrapLongLineForJCL("*\n"); - return jcl; - } + return jcl; + } - private generateCommonJCLFooter(): string { - let jcl = + private generateCommonJCLFooter(): string { + let jcl = this.wrapLongLineForJCL(" SCOPE(" + this.params.arguments.scope + ")\n") + this.wrapLongLineForJCL(" STATE(" + this.params.arguments.targetstate + ")\n"); - if (this.params.arguments.timeout !== undefined) { - jcl = jcl + this.wrapLongLineForJCL(" TIMEOUT(" + this.params.arguments.timeout + ")\n"); - } - if (this.params.arguments.csdgroup !== undefined) { - jcl = jcl + this.wrapLongLineForJCL(" CSDGROUP(" + this.params.arguments.csdgroup + ");\n"); - } - if (this.params.arguments.resgroup !== undefined) { - jcl = jcl + this.wrapLongLineForJCL(" RESGROUP(" + this.params.arguments.resgroup + ");\n"); - } + if (this.params.arguments.timeout !== undefined) { + jcl = jcl + this.wrapLongLineForJCL(" TIMEOUT(" + this.params.arguments.timeout + ")\n"); + } + if (this.params.arguments.csdgroup !== undefined) { + jcl = jcl + this.wrapLongLineForJCL(" CSDGROUP(" + this.params.arguments.csdgroup + ");\n"); + } + if (this.params.arguments.resgroup !== undefined) { + jcl = jcl + this.wrapLongLineForJCL(" RESGROUP(" + this.params.arguments.resgroup + ");\n"); + } - // finally add a terminator - jcl = jcl + "/*\n"; + // finally add a terminator + jcl = jcl + "/*\n"; - return jcl; - } + return jcl; + } - private async createZosMFSession(): Promise { + private async createZosMFSession(): Promise { // Create a zosMF session - let zosmfProfile; - try { - zosmfProfile = this.params.profiles.get("zosmf"); - } - catch (error) { - // No-op, we can cope with there being no profile. - } + let zosmfProfile; + try { + zosmfProfile = this.params.profiles.get("zosmf"); + } + catch (error) { + // No-op, we can cope with there being no profile. + } - if (zosmfProfile === undefined) { - zosmfProfile = {}; - } + if (zosmfProfile === undefined) { + zosmfProfile = {}; + } + + ZosmfConfig.mergeProfile(zosmfProfile, this.params); - ZosmfConfig.mergeProfile(zosmfProfile, this.params); + return ZosmfSession.createBasicZosmfSession(zosmfProfile); + } - return ZosmfSession.createBasicZosmfSession(zosmfProfile); - } + private async checkHLQDatasets(session: any) { - private async checkHLQDatasets(session: any) { + // No need to revalidate multiple times during a push command + if (this.hlqsValidated === true) { + return; + } - // No need to revalidate multiple times during a push command - if (this.hlqsValidated === true) { - return; - } + // Check that the CICS dataset value looks valid and can be viewed + // Access errors will trigger an Exception + const cicspds = this.params.arguments.cicshlq + ".SDFHLOAD"; + let listResp; + try { + listResp = await List.allMembers(session, cicspds, {}); + } + catch (error) { + throw new Error("Validation of --cicshlq dataset failed: " + error.message); + } + if (JSON.stringify(listResp).indexOf("DFHDPLOY") === -1) { + throw new Error("DFHDPLOY not found in SDFHLOAD within the --cicshlq dataset: " + cicspds); + } - // Check that the CICS dataset value looks valid and can be viewed - // Access errors will trigger an Exception - const cicspds = this.params.arguments.cicshlq + ".SDFHLOAD"; - let listResp; - try { - listResp = await List.allMembers(session, cicspds, {}); - } - catch (error) { - throw new Error("Validation of --cicshlq dataset failed: " + error.message); - } - if (JSON.stringify(listResp).indexOf("DFHDPLOY") === -1) { - throw new Error("DFHDPLOY not found in SDFHLOAD within the --cicshlq dataset: " + cicspds); - } + // Check that the CPSM dataset value looks valid and can be viewed + // Access errors will trigger an Exception + const cpsmpds = this.params.arguments.cpsmhlq + ".SEYUAUTH"; + try { + listResp = await List.allMembers(session, cpsmpds, {}); + } + catch (error) { + throw new Error("Validation of --cpsmhlq dataset failed: " + error.message); + } + if (JSON.stringify(listResp).indexOf("EYU9ABSI") === -1) { + throw new Error("EYU9ABSI not found in SEYUAUTH within the --cpsmhlq dataset: " + cpsmpds); + } - // Check that the CPSM dataset value looks valid and can be viewed - // Access errors will trigger an Exception - const cpsmpds = this.params.arguments.cpsmhlq + ".SEYUAUTH"; - try { - listResp = await List.allMembers(session, cpsmpds, {}); - } - catch (error) { - throw new Error("Validation of --cpsmhlq dataset failed: " + error.message); - } - if (JSON.stringify(listResp).indexOf("EYU9ABSI") === -1) { - throw new Error("EYU9ABSI not found in SEYUAUTH within the --cpsmhlq dataset: " + cpsmpds); + this.hlqsValidated = true; } - this.hlqsValidated = true; - } - - private updateProgressBar(action: string) { + private updateProgressBar(action: string) { // Increment the progress bar. This will refresh what the user sees on the console. - this.progressBar.percentComplete += this.PROGRESS_BAR_INCREMENT; - - // Have a look at the status message for the progress bar, has it been updated with - // the jobid yet? If so, parse it out and refresh the message. - if (this.jobId === "UNKNOWN" && this.progressBar.statusMessage) { - const statusWords = this.progressBar.statusMessage.split(" "); - if (statusWords.length >= 2) { - if (statusWords[2] !== undefined && statusWords[2].indexOf("JOB") === 0) { - this.jobId = statusWords[2]; - this.progressBar.statusMessage = "Running DFHDPLOY (" + action + "), jobid " + this.jobId; - - this.endProgressBar(); - // log the jobid for posterity - if (this.params.arguments.verbose) { - this.params.response.console.log(this.progressBar.statusMessage + "\n"); - } - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(this.progressBar.statusMessage); - } - this.startProgressBar(); + this.progressBar.percentComplete += this.PROGRESS_BAR_INCREMENT; + + // Have a look at the status message for the progress bar, has it been updated with + // the jobid yet? If so, parse it out and refresh the message. + if (this.jobId === "UNKNOWN" && this.progressBar.statusMessage) { + const statusWords = this.progressBar.statusMessage.split(" "); + if (statusWords.length >= 2) { + if (statusWords[2] !== undefined && statusWords[2].indexOf("JOB") === 0) { + this.jobId = statusWords[2]; + this.progressBar.statusMessage = "Running DFHDPLOY (" + action + "), jobid " + this.jobId; + + this.endProgressBar(); + // log the jobid for posterity + if (this.params.arguments.verbose) { + this.params.response.console.log(this.progressBar.statusMessage + "\n"); + } + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(this.progressBar.statusMessage); + } + this.startProgressBar(); + } + } } - } - } - // Continue iterating on progress updates until we've reached the max value, - // or until the processing has completed. - if (this.progressBar.percentComplete < this.PROGRESS_BAR_MAX && + // Continue iterating on progress updates until we've reached the max value, + // or until the processing has completed. + if (this.progressBar.percentComplete < this.PROGRESS_BAR_MAX && this.progressBar.stageName === TaskStage.IN_PROGRESS) { - setTimeout(this.updateProgressBar.bind(this), this.PROGRESS_BAR_INTERVAL, action); + setTimeout(this.updateProgressBar.bind(this), this.PROGRESS_BAR_INTERVAL, action); + } } - } - private async submitJCL(jcl: string, action: string, session: any, task?: ITaskWithStatus): Promise { - let spoolOutput: any; - if (task) { - this.progressBar = task; - this.useResponseProgressBar = false; - } + private async submitJCL(jcl: string, action: string, session: any, task?: ITaskWithStatus): Promise { + let spoolOutput: any; + if (task) { + this.progressBar = task; + this.useResponseProgressBar = false; + } - this.progressBar.percentComplete = TaskProgress.TEN_PERCENT; - this.progressBar.statusMessage = "Submitting DFHDPLOY JCL for the " + action + " action"; - this.progressBar.stageName = TaskStage.IN_PROGRESS; - - this.startProgressBar(); - this.jobId = "UNKNOWN"; - this.jobOutput = ""; - - // Refresh the progress bar by 1% every second or so up to a max of 67%. - // SubmitJobs will initialise it to 30% and set it to 70% when it - // completes, we tweak it every so often until then for purely cosmetic purposes. - setTimeout(this.updateProgressBar.bind(this), this.PROGRESS_BAR_INTERVAL, action); - - try { - spoolOutput = await SubmitJobs.submitJclString(session, jcl, { - jclSource: "", - task: this.progressBar, - viewAllSpoolContent: true - }); - } - catch (error) { - this.progressBar.stageName = TaskStage.FAILED; - throw new Error("Failure occurred submitting DFHDPLOY JCL for jobid " + this.jobId + ": '" + error.message + + this.progressBar.percentComplete = TaskProgress.TEN_PERCENT; + this.progressBar.statusMessage = "Submitting DFHDPLOY JCL for the " + action + " action"; + this.progressBar.stageName = TaskStage.IN_PROGRESS; + + this.startProgressBar(); + this.jobId = "UNKNOWN"; + this.jobOutput = ""; + + // Refresh the progress bar by 1% every second or so up to a max of 67%. + // SubmitJobs will initialise it to 30% and set it to 70% when it + // completes, we tweak it every so often until then for purely cosmetic purposes. + setTimeout(this.updateProgressBar.bind(this), this.PROGRESS_BAR_INTERVAL, action); + + try { + spoolOutput = await SubmitJobs.submitJclString(session, jcl, { + jclSource: "", + task: this.progressBar, + viewAllSpoolContent: true + }); + } + catch (error) { + this.progressBar.stageName = TaskStage.FAILED; + throw new Error("Failure occurred submitting DFHDPLOY JCL for jobid " + this.jobId + ": '" + error.message + "'. Most recent status update: '" + this.progressBar.statusMessage + "'."); - } + } - // Find the output - for (const file of spoolOutput) { - // we're looking for the SYSTSPRT output from the DFHDPLOY step. - if (file.ddName === "SYSTSPRT" && file.stepName === "DFHDPLOY") { + // Find the output + for (const file of spoolOutput) { + // we're looking for the SYSTSPRT output from the DFHDPLOY step. + if (file.ddName === "SYSTSPRT" && file.stepName === "DFHDPLOY") { - if (file.data === undefined || file.data.length === 0) { - this.progressBar.stageName = TaskStage.FAILED; - throw new Error("DFHDPLOY did not generate any output for jobid " + this.jobId + + if (file.data === undefined || file.data.length === 0) { + this.progressBar.stageName = TaskStage.FAILED; + throw new Error("DFHDPLOY did not generate any output for jobid " + this.jobId + ". Most recent status update: '" + this.progressBar.statusMessage + "'."); + } + + // log the full output for serviceability to the log + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(file.data); + } + this.jobOutput = file.data; + + // Finish the progress bar + this.progressBar.statusMessage = "Completed DFHDPLOY"; + this.endProgressBar(); + + // Did DFHDPLOY fail? + if (file.data.indexOf("DFHRL2055I") > -1) { + this.progressBar.stageName = TaskStage.FAILED; + // log the error output to the console + this.params.response.console.log(file.data); + throw new Error("DFHDPLOY stopped processing for jobid " + this.jobId + " due to an error."); + } + if (file.data.indexOf("DFHRL2043I") > -1) { + this.progressBar.stageName = TaskStage.COMPLETE; + // log the error output to the console + this.params.response.console.log(file.data); + return "DFHDPLOY completed with warnings."; + } + if (file.data.indexOf("DFHRL2012I") > -1) { + this.progressBar.stageName = TaskStage.COMPLETE; + // only log the output to the console if verbose output is enabled + if (this.params.arguments.verbose) { + this.params.response.console.log(file.data); + } + return "Bundle deployment successful."; + } + if (file.data.indexOf("DFHRL2037I") > -1) { + this.progressBar.stageName = TaskStage.COMPLETE; + // only log the output to the console if verbose output is enabled + if (this.params.arguments.verbose) { + this.params.response.console.log(file.data); + } + return "Bundle undeployment successful."; + } + + this.progressBar.stageName = TaskStage.FAILED; + // log the error output to the console + this.params.response.console.log(file.data); + throw new Error("DFHDPLOY command completed for jobid " + this.jobId + ", but status cannot be determined."); + } } - // log the full output for serviceability to the log - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(file.data); - } - this.jobOutput = file.data; - - // Finish the progress bar - this.progressBar.statusMessage = "Completed DFHDPLOY"; - this.endProgressBar(); - - // Did DFHDPLOY fail? - if (file.data.indexOf("DFHRL2055I") > -1) { - this.progressBar.stageName = TaskStage.FAILED; - // log the error output to the console - this.params.response.console.log(file.data); - throw new Error("DFHDPLOY stopped processing for jobid " + this.jobId + " due to an error."); - } - if (file.data.indexOf("DFHRL2043I") > -1) { - this.progressBar.stageName = TaskStage.COMPLETE; - // log the error output to the console - this.params.response.console.log(file.data); - return "DFHDPLOY completed with warnings."; - } - if (file.data.indexOf("DFHRL2012I") > -1) { - this.progressBar.stageName = TaskStage.COMPLETE; - // only log the output to the console if verbose output is enabled - if (this.params.arguments.verbose) { - this.params.response.console.log(file.data); - } - return "Bundle deployment successful."; - } - if (file.data.indexOf("DFHRL2037I") > -1) { - this.progressBar.stageName = TaskStage.COMPLETE; - // only log the output to the console if verbose output is enabled - if (this.params.arguments.verbose) { - this.params.response.console.log(file.data); - } - return "Bundle undeployment successful."; + // If we haven't found SYSTSPRT then echo JESMSGLG instead + for (const file of spoolOutput) { + if (file.ddName === "JESMSGLG") { + this.progressBar.stageName = TaskStage.FAILED; + // log the error output to the console + this.params.response.console.log(file.data); + throw new Error("DFHDPLOY command completed in error for jobid " + this.jobId + " without generating SYSTSPRT output."); + } } this.progressBar.stageName = TaskStage.FAILED; - // log the error output to the console - this.params.response.console.log(file.data); - throw new Error("DFHDPLOY command completed for jobid " + this.jobId + ", but status cannot be determined."); - } - } - - // If we haven't found SYSTSPRT then echo JESMSGLG instead - for (const file of spoolOutput) { - if (file.ddName === "JESMSGLG") { - this.progressBar.stageName = TaskStage.FAILED; - // log the error output to the console - this.params.response.console.log(file.data); - throw new Error("DFHDPLOY command completed in error for jobid " + this.jobId + " without generating SYSTSPRT output."); - } - } - - this.progressBar.stageName = TaskStage.FAILED; - throw new Error("SYSTSPRT and JESMSGLG output from DFHDPLOY not found for jobid " + this.jobId + + throw new Error("SYSTSPRT and JESMSGLG output from DFHDPLOY not found for jobid " + this.jobId + ". Most recent status update: '" + this.progressBar.statusMessage + "'."); - } + } - private startProgressBar() { - if (this.params.arguments.verbose !== true && this.useResponseProgressBar === true) { - this.params.response.progress.startBar({task: this.progressBar}); + private startProgressBar() { + if (this.params.arguments.verbose !== true && this.useResponseProgressBar === true) { + this.params.response.progress.startBar({task: this.progressBar}); + } } - } - private endProgressBar() { - if (this.params.arguments.verbose !== true && this.useResponseProgressBar === true) { - this.params.response.progress.endBar(); + private endProgressBar() { + if (this.params.arguments.verbose !== true && this.useResponseProgressBar === true) { + this.params.response.progress.endBar(); + } } - } } diff --git a/src/api/BundleDeploy/ParmValidator.ts b/src/api/BundleDeploy/ParmValidator.ts index 33aa11bc..51a616e9 100644 --- a/src/api/BundleDeploy/ParmValidator.ts +++ b/src/api/BundleDeploy/ParmValidator.ts @@ -15,420 +15,420 @@ import { IHandlerParameters, Logger } from "@zowe/imperative"; export class ParmValidator { - public static validateDeploy(params: IHandlerParameters) { - - // Validate the parms that are valid for Deploy - ParmValidator.validateName(params); - ParmValidator.validateBundledir(params); - ParmValidator.validateCicsDeployProfile(params); - ParmValidator.validateCicsplex(params); - ParmValidator.validateScope(params); - ParmValidator.validateCsdgroup(params); - ParmValidator.validateResgroup(params); - ParmValidator.validateDescription(params); - ParmValidator.validateTimeout(params); - ParmValidator.validateCicshlq(params); - ParmValidator.validateCpsmhlq(params); - ParmValidator.validateTargetStateDeploy(params); - ParmValidator.validateVerbose(params); - ParmValidator.validateJobcard(params); - } - - public static validateUndeploy(params: IHandlerParameters) { - - // Validate the parms that are valid for Undeploy - ParmValidator.validateName(params); - ParmValidator.validateCicsDeployProfile(params); - ParmValidator.validateCicsplex(params); - ParmValidator.validateScope(params); - ParmValidator.validateCsdgroup(params); - ParmValidator.validateResgroup(params); - ParmValidator.validateTimeout(params); - ParmValidator.validateCicshlq(params); - ParmValidator.validateCpsmhlq(params); - ParmValidator.validateTargetStateUndeploy(params); - ParmValidator.validateVerbose(params); - ParmValidator.validateJobcard(params); - } - - private static validateName(params: IHandlerParameters) { + public static validateDeploy(params: IHandlerParameters) { + + // Validate the parms that are valid for Deploy + ParmValidator.validateName(params); + ParmValidator.validateBundledir(params); + ParmValidator.validateCicsDeployProfile(params); + ParmValidator.validateCicsplex(params); + ParmValidator.validateScope(params); + ParmValidator.validateCsdgroup(params); + ParmValidator.validateResgroup(params); + ParmValidator.validateDescription(params); + ParmValidator.validateTimeout(params); + ParmValidator.validateCicshlq(params); + ParmValidator.validateCpsmhlq(params); + ParmValidator.validateTargetStateDeploy(params); + ParmValidator.validateVerbose(params); + ParmValidator.validateJobcard(params); + } + + public static validateUndeploy(params: IHandlerParameters) { + + // Validate the parms that are valid for Undeploy + ParmValidator.validateName(params); + ParmValidator.validateCicsDeployProfile(params); + ParmValidator.validateCicsplex(params); + ParmValidator.validateScope(params); + ParmValidator.validateCsdgroup(params); + ParmValidator.validateResgroup(params); + ParmValidator.validateTimeout(params); + ParmValidator.validateCicshlq(params); + ParmValidator.validateCpsmhlq(params); + ParmValidator.validateTargetStateUndeploy(params); + ParmValidator.validateVerbose(params); + ParmValidator.validateJobcard(params); + } + + private static validateName(params: IHandlerParameters) { // Name is mandatory - if (params.arguments.name === undefined) { - throw new Error("--name parameter is not set"); - } + if (params.arguments.name === undefined) { + throw new Error("--name parameter is not set"); + } - if (typeof params.arguments.name !== "string") { - throw new Error("--name parameter is not a string"); - } + if (typeof params.arguments.name !== "string") { + throw new Error("--name parameter is not a string"); + } - const MAX_LEN = 8; - if (params.arguments.name.length > MAX_LEN) { - throw new Error("--name parameter is too long"); - } + const MAX_LEN = 8; + if (params.arguments.name.length > MAX_LEN) { + throw new Error("--name parameter is too long"); + } - if (params.arguments.name === "") { - throw new Error("--name parameter is empty"); + if (params.arguments.name === "") { + throw new Error("--name parameter is empty"); + } } - } - private static validateBundledir(params: IHandlerParameters) { + private static validateBundledir(params: IHandlerParameters) { // bundleDir is mandatory (but only for deploy. not undeploy) - if (params.arguments.bundledir === undefined) { - throw new Error("--bundledir parameter is not set"); - } + if (params.arguments.bundledir === undefined) { + throw new Error("--bundledir parameter is not set"); + } - if (typeof params.arguments.bundledir !== "string") { - throw new Error("--bundledir parameter is not a string"); - } + if (typeof params.arguments.bundledir !== "string") { + throw new Error("--bundledir parameter is not a string"); + } - const MAX_LEN = 255; - if (params.arguments.bundledir.length > MAX_LEN) { - throw new Error("--bundledir parameter is too long"); - } + const MAX_LEN = 255; + if (params.arguments.bundledir.length > MAX_LEN) { + throw new Error("--bundledir parameter is too long"); + } - if (params.arguments.bundledir === "") { - throw new Error("--bundledir parameter is empty"); + if (params.arguments.bundledir === "") { + throw new Error("--bundledir parameter is empty"); + } } - } - private static validateCicsDeployProfile(params: IHandlerParameters) { + private static validateCicsDeployProfile(params: IHandlerParameters) { - // if missing, then CICSPlex and Scope must be set - if (params.arguments["cics-deploy-profile"] === undefined) { - if (params.arguments.cicsplex === undefined || + // if missing, then CICSPlex and Scope must be set + if (params.arguments["cics-deploy-profile"] === undefined) { + if (params.arguments.cicsplex === undefined || params.arguments.scope === undefined) { - throw new Error("either --cics-deploy-profile or both --cicsplex and --scope must be set"); - } - return; - } + throw new Error("either --cics-deploy-profile or both --cicsplex and --scope must be set"); + } + return; + } - if (typeof params.arguments["cics-deploy-profile"] !== "string") { - throw new Error("--cics-deploy-profile parameter is not a string"); - } + if (typeof params.arguments["cics-deploy-profile"] !== "string") { + throw new Error("--cics-deploy-profile parameter is not a string"); + } - if (params.arguments["cics-deploy-profile"] === "") { - throw new Error("--cics-deploy-profile parameter is empty"); - } + if (params.arguments["cics-deploy-profile"] === "") { + throw new Error("--cics-deploy-profile parameter is empty"); + } - // Now check that the profile can be found - const prof = params.profiles.get("cics-deploy"); + // Now check that the profile can be found + const prof = params.profiles.get("cics-deploy"); - // const logger = Logger.getAppLogger(); - // logger.debug("Profile: " + JSON.stringify(prof)); + // const logger = Logger.getAppLogger(); + // logger.debug("Profile: " + JSON.stringify(prof)); - if (prof === undefined) { - throw new Error('cics-deploy-profile "' + params.arguments["cics-deploy-profile"] + '" not found.'); + if (prof === undefined) { + throw new Error('cics-deploy-profile "' + params.arguments["cics-deploy-profile"] + '" not found.'); + } } - } - private static validateCicsplex(params: IHandlerParameters) { + private static validateCicsplex(params: IHandlerParameters) { - if (typeof params.arguments.cicsplex !== "string") { - throw new Error("--cicsplex parameter is not a string"); - } + if (typeof params.arguments.cicsplex !== "string") { + throw new Error("--cicsplex parameter is not a string"); + } - const MAX_LEN = 8; - if (params.arguments.cicsplex.length > MAX_LEN) { - throw new Error("--cicsplex parameter is too long"); - } + const MAX_LEN = 8; + if (params.arguments.cicsplex.length > MAX_LEN) { + throw new Error("--cicsplex parameter is too long"); + } - if (params.arguments.cicsplex === "") { - throw new Error("--cicsplex parameter is empty"); + if (params.arguments.cicsplex === "") { + throw new Error("--cicsplex parameter is empty"); + } } - } - private static validateScope(params: IHandlerParameters) { + private static validateScope(params: IHandlerParameters) { - if (typeof params.arguments.scope !== "string") { - throw new Error("--scope parameter is not a string"); - } + if (typeof params.arguments.scope !== "string") { + throw new Error("--scope parameter is not a string"); + } - const MAX_LEN = 8; - if (params.arguments.scope.length > MAX_LEN) { - throw new Error("--scope parameter is too long"); - } + const MAX_LEN = 8; + if (params.arguments.scope.length > MAX_LEN) { + throw new Error("--scope parameter is too long"); + } - if (params.arguments.scope === "") { - throw new Error("--scope parameter is empty"); + if (params.arguments.scope === "") { + throw new Error("--scope parameter is empty"); + } } - } - private static validateCsdgroup(params: IHandlerParameters) { + private static validateCsdgroup(params: IHandlerParameters) { // csdgroup is optional - if (params.arguments.csdgroup === undefined) { - return; - } + if (params.arguments.csdgroup === undefined) { + return; + } - // if set, it's mutually exclusive with resgroup - if (params.arguments.resgroup !== undefined) { - throw new Error("--csdgroup and --resgroup cannot both be set"); - } + // if set, it's mutually exclusive with resgroup + if (params.arguments.resgroup !== undefined) { + throw new Error("--csdgroup and --resgroup cannot both be set"); + } - if (typeof params.arguments.csdgroup !== "string") { - throw new Error("--csdgroup parameter is not a string"); - } + if (typeof params.arguments.csdgroup !== "string") { + throw new Error("--csdgroup parameter is not a string"); + } - const MAX_LEN = 8; - if (params.arguments.csdgroup.length > MAX_LEN) { - throw new Error("--csdgroup parameter is too long"); - } + const MAX_LEN = 8; + if (params.arguments.csdgroup.length > MAX_LEN) { + throw new Error("--csdgroup parameter is too long"); + } - if (params.arguments.csdgroup === "") { - throw new Error("--csdgroup parameter is empty"); + if (params.arguments.csdgroup === "") { + throw new Error("--csdgroup parameter is empty"); + } } - } - private static validateResgroup(params: IHandlerParameters) { + private static validateResgroup(params: IHandlerParameters) { // resgroup is optional - if (params.arguments.resgroup === undefined) { - return; - } + if (params.arguments.resgroup === undefined) { + return; + } - if (typeof params.arguments.resgroup !== "string") { - throw new Error("--resgroup parameter is not a string"); - } + if (typeof params.arguments.resgroup !== "string") { + throw new Error("--resgroup parameter is not a string"); + } - const MAX_LEN = 8; - if (params.arguments.resgroup.length > MAX_LEN) { - throw new Error("--resgroup parameter is too long"); - } + const MAX_LEN = 8; + if (params.arguments.resgroup.length > MAX_LEN) { + throw new Error("--resgroup parameter is too long"); + } - if (params.arguments.resgroup === "") { - throw new Error("--resgroup parameter is empty"); + if (params.arguments.resgroup === "") { + throw new Error("--resgroup parameter is empty"); + } } - } - private static validateTimeout(params: IHandlerParameters) { + private static validateTimeout(params: IHandlerParameters) { // timeout is optional - if (params.arguments.timeout === undefined) { - return; - } + if (params.arguments.timeout === undefined) { + return; + } - if (Number.isInteger(params.arguments.timeout) === false) { - throw new Error("--timeout parameter is not an integer"); - } + if (Number.isInteger(params.arguments.timeout) === false) { + throw new Error("--timeout parameter is not an integer"); + } - const MAX_VAL = 1800; - if (params.arguments.timeout > MAX_VAL) { - throw new Error("--timeout parameter is too large"); - } + const MAX_VAL = 1800; + if (params.arguments.timeout > MAX_VAL) { + throw new Error("--timeout parameter is too large"); + } - if (params.arguments.timeout < 1) { - throw new Error("--timeout parameter is too small"); + if (params.arguments.timeout < 1) { + throw new Error("--timeout parameter is too small"); + } } - } - private static validateCicshlq(params: IHandlerParameters) { + private static validateCicshlq(params: IHandlerParameters) { // cicshlq is mandatory - if (params.arguments.cicshlq === undefined) { - throw new Error("--cicshlq parameter is not set"); - } + if (params.arguments.cicshlq === undefined) { + throw new Error("--cicshlq parameter is not set"); + } - if (typeof params.arguments.cicshlq !== "string") { - throw new Error("--cicshlq parameter is not a string"); - } + if (typeof params.arguments.cicshlq !== "string") { + throw new Error("--cicshlq parameter is not a string"); + } - const MAX_LEN = 35; - if (params.arguments.cicshlq.length > MAX_LEN) { - throw new Error("--cicshlq parameter is too long"); - } + const MAX_LEN = 35; + if (params.arguments.cicshlq.length > MAX_LEN) { + throw new Error("--cicshlq parameter is too long"); + } - if (params.arguments.cicshlq === "") { - throw new Error("--cicshlq parameter is empty"); + if (params.arguments.cicshlq === "") { + throw new Error("--cicshlq parameter is empty"); + } } - } - private static validateCpsmhlq(params: IHandlerParameters) { + private static validateCpsmhlq(params: IHandlerParameters) { // cpsmhlq is mandatory - if (params.arguments.cpsmhlq === undefined) { - throw new Error("--cpsmhlq parameter is not set"); - } + if (params.arguments.cpsmhlq === undefined) { + throw new Error("--cpsmhlq parameter is not set"); + } - if (typeof params.arguments.cpsmhlq !== "string") { - throw new Error("--cpsmhlq parameter is not a string"); - } + if (typeof params.arguments.cpsmhlq !== "string") { + throw new Error("--cpsmhlq parameter is not a string"); + } - const MAX_LEN = 35; - if (params.arguments.cpsmhlq.length > MAX_LEN) { - throw new Error("--cpsmhlq parameter is too long"); - } + const MAX_LEN = 35; + if (params.arguments.cpsmhlq.length > MAX_LEN) { + throw new Error("--cpsmhlq parameter is too long"); + } - if (params.arguments.cpsmhlq === "") { - throw new Error("--cpsmhlq parameter is empty"); - } - } - - private static wrapJobcard(params: IHandlerParameters) { - if (params.arguments.jobcard.indexOf("\\n") === -1) { - // if the user hasn't embedded new-line characters into the jobcard - // then we'll have to do that ourselves if the value is too long - let jobcardLocal = params.arguments.jobcard; - let jobcardNew = ""; - const MAX_JCL_LINE = 71; - while (jobcardLocal.length > MAX_JCL_LINE) { - const indexOflastComma = jobcardLocal.lastIndexOf(",", MAX_JCL_LINE); - - if (indexOflastComma === -1) { - throw new Error("--jobcard parameter section cannot be split into 72 character lines: '" + jobcardLocal + "'."); - } - - jobcardNew = jobcardNew + jobcardLocal.substring(0, indexOflastComma + 1) + "\n"; - jobcardLocal = "// " + jobcardLocal.substring(indexOflastComma + 1); - } - jobcardNew = jobcardNew + jobcardLocal; - params.arguments.jobcard = jobcardNew; + if (params.arguments.cpsmhlq === "") { + throw new Error("--cpsmhlq parameter is empty"); + } } - else { - // if the user has embedded new-line characters within the jobcard - // then resolve them, the user has taken responsibility for ensuring - // line breaks are in suitable places. - params.arguments.jobcard = params.arguments.jobcard.replace("\\n", "\n"); + + private static wrapJobcard(params: IHandlerParameters) { + if (params.arguments.jobcard.indexOf("\\n") === -1) { + // if the user hasn't embedded new-line characters into the jobcard + // then we'll have to do that ourselves if the value is too long + let jobcardLocal = params.arguments.jobcard; + let jobcardNew = ""; + const MAX_JCL_LINE = 71; + while (jobcardLocal.length > MAX_JCL_LINE) { + const indexOflastComma = jobcardLocal.lastIndexOf(",", MAX_JCL_LINE); + + if (indexOflastComma === -1) { + throw new Error("--jobcard parameter section cannot be split into 72 character lines: '" + jobcardLocal + "'."); + } + + jobcardNew = jobcardNew + jobcardLocal.substring(0, indexOflastComma + 1) + "\n"; + jobcardLocal = "// " + jobcardLocal.substring(indexOflastComma + 1); + } + jobcardNew = jobcardNew + jobcardLocal; + params.arguments.jobcard = jobcardNew; + } + else { + // if the user has embedded new-line characters within the jobcard + // then resolve them, the user has taken responsibility for ensuring + // line breaks are in suitable places. + params.arguments.jobcard = params.arguments.jobcard.replace("\\n", "\n"); + } } - } - private static validateJobcard(params: IHandlerParameters) { + private static validateJobcard(params: IHandlerParameters) { // jobcard is mandatory - if (params.arguments.jobcard === undefined) { - throw new Error("--jobcard parameter is not set"); - } + if (params.arguments.jobcard === undefined) { + throw new Error("--jobcard parameter is not set"); + } - if (typeof params.arguments.jobcard !== "string") { - throw new Error("--jobcard parameter is not a string"); - } + if (typeof params.arguments.jobcard !== "string") { + throw new Error("--jobcard parameter is not a string"); + } - if (params.arguments.jobcard === "") { - throw new Error("--jobcard parameter is empty"); - } + if (params.arguments.jobcard === "") { + throw new Error("--jobcard parameter is empty"); + } - // handle long jobcards - ParmValidator.wrapJobcard(params); + // handle long jobcards + ParmValidator.wrapJobcard(params); - // Strip leading and trailing quotes, if they're there - params.arguments.jobcard = params.arguments.jobcard.replace(/^"(.*)"$/, "$1"); - params.arguments.jobcard = params.arguments.jobcard.replace(/^'(.*)'$/, "$1"); + // Strip leading and trailing quotes, if they're there + params.arguments.jobcard = params.arguments.jobcard.replace(/^"(.*)"$/, "$1"); + params.arguments.jobcard = params.arguments.jobcard.replace(/^'(.*)'$/, "$1"); - // split the jobcard into a comma separated list - const jobcardParts = params.arguments.jobcard.split(","); - let firstPart = jobcardParts[0].trim(); + // split the jobcard into a comma separated list + const jobcardParts = params.arguments.jobcard.split(","); + let firstPart = jobcardParts[0].trim(); - // check that it starts with '//' - if (firstPart.indexOf("//") !== 0) { + // check that it starts with '//' + if (firstPart.indexOf("//") !== 0) { - // gitbash can swallow a '/' character. If we only have one then add another. - if (firstPart.startsWith("/")) { - params.arguments.jobcard = "/" + params.arguments.jobcard; - firstPart = "/" + firstPart; - } - else { - throw new Error("--jobcard parameter does not start with //"); - } - } + // gitbash can swallow a '/' character. If we only have one then add another. + if (firstPart.startsWith("/")) { + params.arguments.jobcard = "/" + params.arguments.jobcard; + firstPart = "/" + firstPart; + } + else { + throw new Error("--jobcard parameter does not start with //"); + } + } - // split the first section of the jobcard into chunks - // e.g. //DFHDPLOY JOB EXAMPLE, - const firstPartParts = firstPart.split(" "); + // split the first section of the jobcard into chunks + // e.g. //DFHDPLOY JOB EXAMPLE, + const firstPartParts = firstPart.split(" "); - // check the initial word is max 10 chars long, eg //DFHDPLOY - const jobname = firstPartParts[0].trim(); - const MAX_JOBNAME = 10; - const MIN_JOBNAME = 3; - if (jobname.length > MAX_JOBNAME || jobname.length < MIN_JOBNAME) { - throw new Error("--jobcard parameter does not start with a suitable jobname: '" + jobname + " '"); - } + // check the initial word is max 10 chars long, eg //DFHDPLOY + const jobname = firstPartParts[0].trim(); + const MAX_JOBNAME = 10; + const MIN_JOBNAME = 3; + if (jobname.length > MAX_JOBNAME || jobname.length < MIN_JOBNAME) { + throw new Error("--jobcard parameter does not start with a suitable jobname: '" + jobname + " '"); + } - // Check that there is a second word - if (firstPartParts.length < 2) { - throw new Error("--jobcard parameter does not have JOB keyword after the jobname."); - } + // Check that there is a second word + if (firstPartParts.length < 2) { + throw new Error("--jobcard parameter does not have JOB keyword after the jobname."); + } - // check the second word is 'JOB' - const jobkeyword = firstPartParts[1].trim(); - if (jobkeyword !== "JOB") { - throw new Error("--jobcard parameter does not have JOB keyword after the jobname. Expected 'JOB' but found '" + jobkeyword + "'"); + // check the second word is 'JOB' + const jobkeyword = firstPartParts[1].trim(); + if (jobkeyword !== "JOB") { + throw new Error("--jobcard parameter does not have JOB keyword after the jobname. Expected 'JOB' but found '" + jobkeyword + "'"); + } } - } - private static validateTargetStateDeploy(params: IHandlerParameters) { + private static validateTargetStateDeploy(params: IHandlerParameters) { // targetstate is mandatory (a default value should be set by Imperative) - if (params.arguments.targetstate === undefined) { - throw new Error("--targetstate parameter is not set"); - } + if (params.arguments.targetstate === undefined) { + throw new Error("--targetstate parameter is not set"); + } - if (typeof params.arguments.targetstate !== "string") { - throw new Error("--targetstate parameter is not a string"); - } + if (typeof params.arguments.targetstate !== "string") { + throw new Error("--targetstate parameter is not a string"); + } - if (params.arguments.targetstate === "") { - throw new Error("--targetstate parameter is empty"); - } + if (params.arguments.targetstate === "") { + throw new Error("--targetstate parameter is empty"); + } - // tolerate mixed case - params.arguments.targetstate = params.arguments.targetstate.toUpperCase(); + // tolerate mixed case + params.arguments.targetstate = params.arguments.targetstate.toUpperCase(); - if (params.arguments.targetstate !== "DISABLED" && + if (params.arguments.targetstate !== "DISABLED" && params.arguments.targetstate !== "ENABLED" && params.arguments.targetstate !== "AVAILABLE") { - throw new Error("--targetstate has invalid value. Found " + + throw new Error("--targetstate has invalid value. Found " + params.arguments.targetstate + " but expected one of DISABLED, ENABLED or AVAILABLE."); + } } - } - private static validateTargetStateUndeploy(params: IHandlerParameters) { + private static validateTargetStateUndeploy(params: IHandlerParameters) { // targetstate is mandatory (a default value should be set by Imperative) - if (params.arguments.targetstate === undefined) { - throw new Error("--targetstate parameter is not set"); - } + if (params.arguments.targetstate === undefined) { + throw new Error("--targetstate parameter is not set"); + } - if (typeof params.arguments.targetstate !== "string") { - throw new Error("--targetstate parameter is not a string"); - } + if (typeof params.arguments.targetstate !== "string") { + throw new Error("--targetstate parameter is not a string"); + } - if (params.arguments.targetstate === "") { - throw new Error("--targetstate parameter is empty"); - } + if (params.arguments.targetstate === "") { + throw new Error("--targetstate parameter is empty"); + } - // tolerate mixed case - params.arguments.targetstate = params.arguments.targetstate.toUpperCase(); + // tolerate mixed case + params.arguments.targetstate = params.arguments.targetstate.toUpperCase(); - if (params.arguments.targetstate !== "UNAVAILABLE" && + if (params.arguments.targetstate !== "UNAVAILABLE" && params.arguments.targetstate !== "DISABLED" && params.arguments.targetstate !== "DISCARDED") { - throw new Error("--targetstate has invalid value. Found " + + throw new Error("--targetstate has invalid value. Found " + params.arguments.targetstate + " but expected one of UNAVAILABLE, DISABLED or DISCARDED."); + } } - } - private static validateVerbose(params: IHandlerParameters) { + private static validateVerbose(params: IHandlerParameters) { // verbose is optional - if (params.arguments.verbose === undefined) { - return; - } + if (params.arguments.verbose === undefined) { + return; + } - if (typeof params.arguments.verbose !== "boolean") { - throw new Error("--verbose parameter is not boolean"); + if (typeof params.arguments.verbose !== "boolean") { + throw new Error("--verbose parameter is not boolean"); + } } - } - private static validateDescription(params: IHandlerParameters) { + private static validateDescription(params: IHandlerParameters) { // description is optional - if (params.arguments.description === undefined) { - return; - } + if (params.arguments.description === undefined) { + return; + } - if (typeof params.arguments.description !== "string") { - throw new Error("--description parameter is not a string"); - } + if (typeof params.arguments.description !== "string") { + throw new Error("--description parameter is not a string"); + } - const MAX_LEN = 58; - if (params.arguments.description.length > MAX_LEN) { - throw new Error("--description parameter is too long"); - } + const MAX_LEN = 58; + if (params.arguments.description.length > MAX_LEN) { + throw new Error("--description parameter is too long"); + } - if (params.arguments.description === "") { - throw new Error("--description parameter is empty"); + if (params.arguments.description === "") { + throw new Error("--description parameter is empty"); + } } - } } diff --git a/src/api/BundlePush/BundlePusher.ts b/src/api/BundlePush/BundlePusher.ts index 7ed4d0f5..863c5ff8 100644 --- a/src/api/BundlePush/BundlePusher.ts +++ b/src/api/BundlePush/BundlePusher.ts @@ -30,806 +30,807 @@ import { CmciConfig } from "./CmciConfig"; */ export class BundlePusher { - private params: IHandlerParameters; - private localDirectory: string; - private sshOutputText: string = ""; - private path = require("path"); - private fs = require("fs"); - private progressBar: ITaskWithStatus; - private defaultRemoteNodehomeCmd = "export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\""; - private envSetupCommand = "export _BPXK_AUTOCVT=ON"; - - /** + private params: IHandlerParameters; + private localDirectory: string; + private sshOutputText: string = ""; + private path = require("path"); + private fs = require("fs"); + private progressBar: ITaskWithStatus; + private defaultRemoteNodehomeCmd = "export PATH=\"$PATH:/usr/lpp/IBM/cnj/v8r0/IBM/node-latest-os390-s390x/bin\""; + private envSetupCommand = "export _BPXK_AUTOCVT=ON"; + + /** * Constructor for a BundlePusher. * @param {IHandlerParameters} params - The Imperative handler parameters * @param {string} localDirectory - The bundle directory. * @throws ImperativeError * @memberof BundlePusher */ - constructor(params: IHandlerParameters, localDirectory: string) { + constructor(params: IHandlerParameters, localDirectory: string) { - this.params = params; - this.localDirectory = localDirectory; - this.validateParameters(); + this.params = params; + this.localDirectory = localDirectory; + this.validateParameters(); - // The targetdir may contain escaped slashes, get rid of them - this.params.arguments.targetdir = this.path.posix.normalize(this.params.arguments.targetdir); + // The targetdir may contain escaped slashes, get rid of them + this.params.arguments.targetdir = this.path.posix.normalize(this.params.arguments.targetdir); - // Set an initial bundledir value for validation purposes (we'll replace it with a better value shortly) - this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, this.params.arguments.name); - } + // Set an initial bundledir value for validation purposes (we'll replace it with a better value shortly) + this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, this.params.arguments.name); + } - public async performPush(): Promise { + public async performPush(): Promise { // Start by validating any parameters that will be used by the deploy action, // this should flush out most input errors before we go on to attempt upload // of the bundle - const bd = new BundleDeployer(this.params); - bd.validateDeployParms(); + const bd = new BundleDeployer(this.params); + bd.validateDeployParms(); - // Check that the current working directory is a CICS bundle - const bundle = new Bundle(this.localDirectory, true, true); - bundle.validate(); + // Check that the current working directory is a CICS bundle + const bundle = new Bundle(this.localDirectory, true, true); + bundle.validate(); - // If the bundle has an id, use it in the target directory name - if (bundle.getId() !== undefined) { - this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, bundle.getId()) + + // If the bundle has an id, use it in the target directory name + if (bundle.getId() !== undefined) { + this.params.arguments.bundledir = this.path.posix.join(this.params.arguments.targetdir, bundle.getId()) + "_" + bundle.getVersion(); - } - - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug("Loading profiles"); - } - - // Get the profiles - const zosMFProfile = this.getProfile("zosmf"); - const sshProfile = this.getProfile("ssh"); - let cicsProfile = this.getProfile("cics"); - ZosmfConfig.mergeProfile(zosMFProfile, this.params); - SshConfig.mergeProfile(sshProfile, this.params); - CmciConfig.mergeProfile(cicsProfile, this.params); - - // The cics profile is optional, detect whether it has been set (or constructed) - if (Object.keys(cicsProfile).length === 0) { - cicsProfile = undefined; - } + } - // Now detect any mismatches between the values from the profiles - this.validateProfiles(zosMFProfile, sshProfile, cicsProfile); + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug("Loading profiles"); + } + // Get the profiles + const zosMFProfile = this.getProfile("zosmf"); + const sshProfile = this.getProfile("ssh"); + let cicsProfile = this.getProfile("cics"); + ZosmfConfig.mergeProfile(zosMFProfile, this.params); + SshConfig.mergeProfile(sshProfile, this.params); + CmciConfig.mergeProfile(cicsProfile, this.params); + + // The cics profile is optional, detect whether it has been set (or constructed) + if (Object.keys(cicsProfile).length === 0) { + cicsProfile = undefined; + } - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug("Creating sessions"); - } + // Now detect any mismatches between the values from the profiles + this.validateProfiles(zosMFProfile, sshProfile, cicsProfile); - // Create a zOSMF session - const zosMFSession = await this.createZosMFSession(zosMFProfile); - // Create an SSH session - const sshSession = await this.createSshSession(sshProfile); - // If relevant, start a CICS session - const cicsSession = await this.createCicsSession(cicsProfile); - // Start a progress bar (but only in non-verbose mode) - this.progressBar = { percentComplete: 0, - statusMessage: "Starting Push operation", - stageName: TaskStage.IN_PROGRESS }; - this.startProgressBar(); + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug("Creating sessions"); + } - // Attempt to make the target bundledir - await this.makeBundleDir(zosMFSession); + // Create a zOSMF session + const zosMFSession = await this.createZosMFSession(zosMFProfile); + // Create an SSH session + const sshSession = await this.createSshSession(sshProfile); + // If relevant, start a CICS session + const cicsSession = await this.createCicsSession(cicsProfile); - // Check that the remote bundledir is suitable. - await this.validateBundleDirExistsAndIsEmpty(zosMFSession); + // Start a progress bar (but only in non-verbose mode) + this.progressBar = { percentComplete: 0, + statusMessage: "Starting Push operation", + stageName: TaskStage.IN_PROGRESS }; + this.startProgressBar(); - // If --overwrite is set then undeploy any existing bundle from CICS - if (this.params.arguments.overwrite) { - await this.undeployExistingBundle(zosMFSession, bd); - } + // Attempt to make the target bundledir + await this.makeBundleDir(zosMFSession); - // Find all of the package.json files in the Bundle - const packageJsonFiles: string[] = []; - this.findAllPackageJSONDirs(this.localDirectory, this.params.arguments.bundledir, packageJsonFiles); + // Check that the remote bundledir is suitable. + await this.validateBundleDirExistsAndIsEmpty(zosMFSession); - // If --overwrite is set then empty the remote directory structure - if (this.params.arguments.overwrite) { - // Run 'npm uninstall' for each package.json file that exists in the bundle. - // This is a courtesy to give npm a chance to clean up itself, we have seen - // things get installed that are difficult to remove simply by deleting the - // directory. - try { - await this.runAllNpmUninstalls(sshSession, packageJsonFiles); - } - catch (error) { - // Something went wrong, but never mind, we'll destroy the entire directory in - // a moment. - } + // If --overwrite is set then undeploy any existing bundle from CICS + if (this.params.arguments.overwrite) { + await this.undeployExistingBundle(zosMFSession, bd); + } - // Now delete the directory - await this.deleteBundleDirContents(sshSession); - } + // Find all of the package.json files in the Bundle + const packageJsonFiles: string[] = []; + this.findAllPackageJSONDirs(this.localDirectory, this.params.arguments.bundledir, packageJsonFiles); + + // If --overwrite is set then empty the remote directory structure + if (this.params.arguments.overwrite) { + // Run 'npm uninstall' for each package.json file that exists in the bundle. + // This is a courtesy to give npm a chance to clean up itself, we have seen + // things get installed that are difficult to remove simply by deleting the + // directory. + try { + await this.runAllNpmUninstalls(sshSession, packageJsonFiles); + } + catch (error) { + // Something went wrong, but never mind, we'll destroy the entire directory in + // a moment. + } + + // Now delete the directory + await this.deleteBundleDirContents(sshSession); + } - // Upload the bundle - await this.uploadBundle(zosMFSession); + // Upload the bundle + await this.uploadBundle(zosMFSession); - // Run 'npm install' for each package.json file that exists in the bundle - await this.runAllNpmInstalls(sshSession, packageJsonFiles); + // Run 'npm install' for each package.json file that exists in the bundle + await this.runAllNpmInstalls(sshSession, packageJsonFiles); - // Run DFHDPLOY to install the bundle (note that this will end the progress bar) - await this.deployBundle(zosMFSession, bd, cicsSession, bundle); + // Run DFHDPLOY to install the bundle (note that this will end the progress bar) + await this.deployBundle(zosMFSession, bd, cicsSession, bundle); - return "PUSH operation completed"; - } + return "PUSH operation completed"; + } - private validateParameters() { + private validateParameters() { // Most of the parameters are validated by the bundle deployer, but we have // to check the --name and --targetdir parameters here, as they are used // to construct one of the values used by the BundleDeployer. - this.validateName(); - this.validateTargetdir(); - } + this.validateName(); + this.validateTargetdir(); + } - private validateName() { + private validateName() { // Name is mandatory - if (this.params.arguments.name === undefined) { - throw new Error("--name parameter is not set"); - } + if (this.params.arguments.name === undefined) { + throw new Error("--name parameter is not set"); + } - if (typeof this.params.arguments.name !== "string") { - throw new Error("--name parameter is not a string"); - } + if (typeof this.params.arguments.name !== "string") { + throw new Error("--name parameter is not a string"); + } - const MAX_LEN = 8; - if (this.params.arguments.name.length > MAX_LEN) { - throw new Error("--name parameter is too long"); - } + const MAX_LEN = 8; + if (this.params.arguments.name.length > MAX_LEN) { + throw new Error("--name parameter is too long"); + } - if (this.params.arguments.name === "") { - throw new Error("--name parameter is empty"); + if (this.params.arguments.name === "") { + throw new Error("--name parameter is empty"); + } } - } - private validateTargetdir() { + private validateTargetdir() { // targetdir is mandatory - if (this.params.arguments.targetdir === undefined) { - throw new Error("--targetdir parameter is not set"); - } - - if (typeof this.params.arguments.targetdir !== "string") { - throw new Error("--targetdir parameter is not a string"); - } - - const MAX_LEN = 255; - if (this.params.arguments.targetdir.length > MAX_LEN) { - throw new Error("--targetdir parameter is too long"); - } + if (this.params.arguments.targetdir === undefined) { + throw new Error("--targetdir parameter is not set"); + } - if (this.params.arguments.targetdir === "") { - throw new Error("--targetdir parameter is empty"); - } - } + if (typeof this.params.arguments.targetdir !== "string") { + throw new Error("--targetdir parameter is not a string"); + } - private getProfile(type: string): IProfile { - let profile; - try { - profile = this.params.profiles.get(type); - } - catch (error) { - // Tolerate errors - } + const MAX_LEN = 255; + if (this.params.arguments.targetdir.length > MAX_LEN) { + throw new Error("--targetdir parameter is too long"); + } - if (profile === undefined) { - profile = {}; + if (this.params.arguments.targetdir === "") { + throw new Error("--targetdir parameter is empty"); + } } - return profile; - } - - private issueWarning(msg: string) { - const warningMsg = "WARNING: " + msg + "\n"; - this.issueMessage(warningMsg); - } + private getProfile(type: string): IProfile { + let profile; + try { + profile = this.params.profiles.get(type); + } + catch (error) { + // Tolerate errors + } - private issueMessage(msg: string) { - this.params.response.console.log(Buffer.from(msg)); - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.warn(msg); - } - } + if (profile === undefined) { + profile = {}; + } - private validateProfiles(zosmfProfile: IProfile, sshProfile: IProfile, cicsProfile: IProfile) { - // Do the required profiles share the same host name? - let sameHostAndUser = true; - if (zosmfProfile.host !== sshProfile.host) { - sameHostAndUser = false; - this.issueWarning("--ssh-host value '" + sshProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'."); + return profile; } - // Do the required profiles share the same user name? - if (zosmfProfile.user.toUpperCase() !== sshProfile.user.toUpperCase()) { - sameHostAndUser = false; - this.issueWarning("--ssh-user value '" + sshProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'."); + private issueWarning(msg: string) { + const warningMsg = "WARNING: " + msg + "\n"; + this.issueMessage(warningMsg); } - // If the zoSMF user and host are the same then validate that the passwords are the same too. - // It's possible, especially over a password change, that one profile may have been updated - // and not the other. Attemps to use the wrong password could result in the account being revoked. - if (sameHostAndUser) { - if (sshProfile.password !== undefined) { - if (zosmfProfile.password !== sshProfile.password) { - throw new Error("Different passwords are specified for the same user ID in the zosmf and ssh configurations."); + private issueMessage(msg: string) { + this.params.response.console.log(Buffer.from(msg)); + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.warn(msg); } - } } - // Is the optional CICS profile compatible? - if (cicsProfile !== undefined) { - sameHostAndUser = true; - if (zosmfProfile.host !== cicsProfile.host) { - sameHostAndUser = false; - this.issueWarning("--cics-host value '" + cicsProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'."); - } - if (zosmfProfile.user.toUpperCase() !== cicsProfile.user.toUpperCase()) { - sameHostAndUser = false; - this.issueWarning("--cics-user value '" + cicsProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'."); - } + private validateProfiles(zosmfProfile: IProfile, sshProfile: IProfile, cicsProfile: IProfile) { + // Do the required profiles share the same host name? + let sameHostAndUser = true; + if (zosmfProfile.host !== sshProfile.host) { + sameHostAndUser = false; + this.issueWarning("--ssh-host value '" + sshProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'."); + } - if (sameHostAndUser) { - if (zosmfProfile.password !== cicsProfile.password) { - throw new Error("Different passwords are specified for the same user ID in the zosmf and cics configurations."); + // Do the required profiles share the same user name? + if (zosmfProfile.user.toUpperCase() !== sshProfile.user.toUpperCase()) { + sameHostAndUser = false; + this.issueWarning("--ssh-user value '" + sshProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'."); } - } - } - } - private async createZosMFSession(zosmfProfile: IProfile): Promise { - try { - return ZosmfSession.createBasicZosmfSession(zosmfProfile); - } - catch (error) { - throw new Error("Failure occurred creating a zosmf session: " + error.message); - } - } + // If the zoSMF user and host are the same then validate that the passwords are the same too. + // It's possible, especially over a password change, that one profile may have been updated + // and not the other. Attemps to use the wrong password could result in the account being revoked. + if (sameHostAndUser) { + if (sshProfile.password !== undefined) { + if (zosmfProfile.password !== sshProfile.password) { + throw new Error("Different passwords are specified for the same user ID in the zosmf and ssh configurations."); + } + } + } - private async createSshSession(sshProfile: IProfile): Promise { - try { - return SshSession.createBasicSshSession(sshProfile); - } - catch (error) { - throw new Error("Failure occurred creating an ssh session: " + error.message); + // Is the optional CICS profile compatible? + if (cicsProfile !== undefined) { + sameHostAndUser = true; + if (zosmfProfile.host !== cicsProfile.host) { + sameHostAndUser = false; + this.issueWarning("--cics-host value '" + cicsProfile.host + "' does not match --zosmf-host value '" + zosmfProfile.host + "'."); + } + if (zosmfProfile.user.toUpperCase() !== cicsProfile.user.toUpperCase()) { + sameHostAndUser = false; + this.issueWarning("--cics-user value '" + cicsProfile.user + "' does not match --zosmf-user value '" + zosmfProfile.user + "'."); + } + + if (sameHostAndUser) { + if (zosmfProfile.password !== cicsProfile.password) { + throw new Error("Different passwords are specified for the same user ID in the zosmf and cics configurations."); + } + } + } } - } - private async createCicsSession(cicsProfile: IProfile): Promise { - if (cicsProfile === undefined) { - return undefined; + private async createZosMFSession(zosmfProfile: IProfile): Promise { + try { + return ZosmfSession.createBasicZosmfSession(zosmfProfile); + } + catch (error) { + throw new Error("Failure occurred creating a zosmf session: " + error.message); + } } - // At time of writing, the CicsSession object in the @zowe/cics project isn't - // accessible, so the following code is copied out of CicsSession.createBasicCicsSession(). - try { - return new Session({ - type: "basic", - hostname: cicsProfile.host, - port: cicsProfile.port, - user: cicsProfile.user, - password: cicsProfile.password, - basePath: cicsProfile.basePath, - protocol: cicsProfile.protocol || "http", - rejectUnauthorized: cicsProfile.rejectUnauthorized - }); - } - catch (error) { - throw new Error("Failure occurred creating a cics session: " + error.message); + private async createSshSession(sshProfile: IProfile): Promise { + try { + return SshSession.createBasicSshSession(sshProfile); + } + catch (error) { + throw new Error("Failure occurred creating an ssh session: " + error.message); + } } - } - - private async validateBundleDirExistsAndIsEmpty(zosMFSession: any) { - try { - this.updateStatus("Accessing contents of remote bundle directory"); - - const fileListResponse = await List.fileList(zosMFSession, this.params.arguments.bundledir, {}); - - if (!fileListResponse.success) { - throw new Error("Command Failed."); - } - - if (fileListResponse.apiResponse === undefined) { - throw new Error("Command response is empty."); - } - if (fileListResponse.apiResponse.items === undefined) { - throw new Error("Command response items are missing."); - } - - // There are always at least two files in all directories: . and .. - const MIN_FILES = 2; + private async createCicsSession(cicsProfile: IProfile): Promise { + if (cicsProfile === undefined) { + return undefined; + } - // Check that if there are files in the directory, one of them is called META-INF - let foundMETAINF = false; - if (fileListResponse.apiResponse.items.length > MIN_FILES) { - for (const file of fileListResponse.apiResponse.items) { - if (file.name === "META-INF") { - foundMETAINF = true; - } + // At time of writing, the CicsSession object in the @zowe/cics project isn't + // accessible, so the following code is copied out of CicsSession.createBasicCicsSession(). + try { + return new Session({ + type: "basic", + hostname: cicsProfile.host, + port: cicsProfile.port, + user: cicsProfile.user, + password: cicsProfile.password, + basePath: cicsProfile.basePath, + protocol: cicsProfile.protocol || "http", + rejectUnauthorized: cicsProfile.rejectUnauthorized + }); } - if (!foundMETAINF) { - throw new Error("The remote directory is already populated and does not contain a bundle."); + catch (error) { + throw new Error("Failure occurred creating a cics session: " + error.message); } - } - - // Check that --overwrite is set if the directory is not empty - if (fileListResponse.apiResponse.items.length > MIN_FILES && this.params.arguments.overwrite !== true) { - throw new Error("The remote directory has existing content and --overwrite has not been set."); - } } - catch (error) { - throw new Error("A problem occurred accessing remote bundle directory '" + this.params.arguments.bundledir + + + private async validateBundleDirExistsAndIsEmpty(zosMFSession: any) { + try { + this.updateStatus("Accessing contents of remote bundle directory"); + + const fileListResponse = await List.fileList(zosMFSession, this.params.arguments.bundledir, {}); + + if (!fileListResponse.success) { + throw new Error("Command Failed."); + } + + if (fileListResponse.apiResponse === undefined) { + throw new Error("Command response is empty."); + } + + if (fileListResponse.apiResponse.items === undefined) { + throw new Error("Command response items are missing."); + } + + // There are always at least two files in all directories: . and .. + const MIN_FILES = 2; + + // Check that if there are files in the directory, one of them is called META-INF + let foundMETAINF = false; + if (fileListResponse.apiResponse.items.length > MIN_FILES) { + for (const file of fileListResponse.apiResponse.items) { + if (file.name === "META-INF") { + foundMETAINF = true; + } + } + if (!foundMETAINF) { + throw new Error("The remote directory is already populated and does not contain a bundle."); + } + } + + // Check that --overwrite is set if the directory is not empty + if (fileListResponse.apiResponse.items.length > MIN_FILES && this.params.arguments.overwrite !== true) { + throw new Error("The remote directory has existing content and --overwrite has not been set."); + } + } + catch (error) { + throw new Error("A problem occurred accessing remote bundle directory '" + this.params.arguments.bundledir + "'. Problem is: " + error.message); + } } - } - private async undeployExistingBundle(zosMFSession: AbstractSession, bd: BundleDeployer) { + private async undeployExistingBundle(zosMFSession: AbstractSession, bd: BundleDeployer) { // End the current progress bar so that UNDEPLOY can create its own - this.updateStatus("Undeploying bundle '" + this.params.arguments.name + "' from CICS"); - - const targetstateLocal = this.params.arguments.targetstate; - this.params.arguments.targetstate = "DISCARDED"; - const subtask = new SubtaskWithStatus(this.progressBar, TaskProgress.THIRTY_PERCENT); - await bd.undeployBundle(zosMFSession, subtask); - this.params.arguments.targetstate = targetstateLocal; - - // Resume the current progress bar - this.endProgressBar(); - this.updateStatus("Undeploy complete"); - this.startProgressBar(); - } - - private async deployBundle(zosMFSession: AbstractSession, bd: BundleDeployer, - cicsSession: AbstractSession, bundle: Bundle) { - // End the current progress bar so that DEPLOY can create its own - this.updateStatus("Deploying bundle '" + this.params.arguments.name + "' to CICS"); - const subtask = new SubtaskWithStatus(this.progressBar, TaskProgress.THIRTY_PERCENT); + this.updateStatus("Undeploying bundle '" + this.params.arguments.name + "' from CICS"); - let deployError: Error; - let dfhdployOutput = ""; - try { - await bd.deployBundle(zosMFSession, subtask); - } - catch (error) { - // temporarily ignore the error as we might want to generate additional resource - // specific diagnostics even if something went wrong. - deployError = error; - } - dfhdployOutput = bd.getJobOutput(); + const targetstateLocal = this.params.arguments.targetstate; + this.params.arguments.targetstate = "DISCARDED"; + const subtask = new SubtaskWithStatus(this.progressBar, TaskProgress.THIRTY_PERCENT); + await bd.undeployBundle(zosMFSession, subtask); + this.params.arguments.targetstate = targetstateLocal; - // End the main progress bar - this.progressBar.percentComplete = TaskProgress.ONE_HUNDRED_PERCENT; - this.endProgressBar(); - if (deployError === undefined) { - this.updateStatus("Deploy complete"); - } - else { - this.updateStatus("Deploy ended with errors"); + // Resume the current progress bar + this.endProgressBar(); + this.updateStatus("Undeploy complete"); + this.startProgressBar(); } - // Collect general information about the regions in the CICSplex scope - let deployMessages = await this.generateGeneralDiagnostics(cicsSession); + private async deployBundle(zosMFSession: AbstractSession, bd: BundleDeployer, + cicsSession: AbstractSession, bundle: Bundle) { + // End the current progress bar so that DEPLOY can create its own + this.updateStatus("Deploying bundle '" + this.params.arguments.name + "' to CICS"); + const subtask = new SubtaskWithStatus(this.progressBar, TaskProgress.THIRTY_PERCENT); + + let deployError: Error; + let dfhdployOutput = ""; + try { + await bd.deployBundle(zosMFSession, subtask); + } + catch (error) { + // temporarily ignore the error as we might want to generate additional resource + // specific diagnostics even if something went wrong. + deployError = error; + } + dfhdployOutput = bd.getJobOutput(); + + // End the main progress bar + this.progressBar.percentComplete = TaskProgress.ONE_HUNDRED_PERCENT; + this.endProgressBar(); + if (deployError === undefined) { + this.updateStatus("Deploy complete"); + } + else { + this.updateStatus("Deploy ended with errors"); + } + + // Collect general information about the regions in the CICSplex scope + let deployMessages = await this.generateGeneralDiagnostics(cicsSession); - if (deployError !== undefined && dfhdployOutput.indexOf("DFHRL2067") === -1) { + if (deployError !== undefined && dfhdployOutput.indexOf("DFHRL2067") === -1) { // If we have an error, but DFHDPLOY did not report that some bundleparts are disabled, // we can assume bundle didn't install at all. In this case skip generation of // Node.js diagnostics. - deployMessages += "DFHDPLOY output implied the bundle failed to install. Check the output above for further information. "; - deployMessages += "Consider examining the JESMSGLG, MSGUSR, SYSPRINT and SYSOUT spool files of the CICS region job, "; - deployMessages += "or consult your CICS system programmer.\n"; - } else if (deployMessages !== "" && bundle.containsDefinitionsOfType("http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP")) { - // Generate additional diagnostic output for Node.js - deployMessages += await this.generateNodejsSpecificDiagnostics(cicsSession); - } + deployMessages += "DFHDPLOY output implied the bundle failed to install. Check the output above for further information. "; + deployMessages += "Consider examining the JESMSGLG, MSGUSR, SYSPRINT and SYSOUT spool files of the CICS region job, "; + deployMessages += "or consult your CICS system programmer.\n"; + } else if (deployMessages !== "" && bundle.containsDefinitionsOfType("http://www.ibm.com/xmlns/prod/cics/bundle/NODEJSAPP")) { + // Generate additional diagnostic output for Node.js + deployMessages += await this.generateNodejsSpecificDiagnostics(cicsSession); + } - // Report any console messages now - this.issueMessage(deployMessages); + // Report any console messages now + this.issueMessage(deployMessages); - // Now rethrow the original error, if there was one. - if (deployError !== undefined) { - throw deployError; + // Now rethrow the original error, if there was one. + if (deployError !== undefined) { + throw deployError; + } } - } - private sshOutput(data: string) { + private sshOutput(data: string) { // If verbose output is requested then log SSH output directly to the console - if (this.params.arguments.verbose) { - this.params.response.console.log(Buffer.from(data)); - } - this.sshOutputText += data; - } - - private async makeBundleDir(zosMFSession: any) { - if (this.params.arguments.verbose) { - this.updateStatus("Making remote bundle directory '" + this.params.arguments.bundledir + "'"); - } - else { - this.updateStatus("Making remote bundle directory"); + if (this.params.arguments.verbose) { + this.params.response.console.log(Buffer.from(data)); + } + this.sshOutputText += data; } - const WARNING = 4; - const ALREADY_EXISTS = 19; - const EIGHT = 8; - const TARGET_DIR_NOT_EXIST = 93651005; - const NO_PERMISSION = -276865003; - try { - await Create.uss(zosMFSession, this.params.arguments.bundledir, "directory"); - } - catch (error) { - if (error.causeErrors !== undefined) - { - let cause; - if (typeof error.causeErrors !== "object") - { - try { - cause = JSON.parse(error.causeErrors); - } - catch (error) { - // whatever we received here it wasn't JSON. Oh well, never mind. - } + private async makeBundleDir(zosMFSession: any) { + if (this.params.arguments.verbose) { + this.updateStatus("Making remote bundle directory '" + this.params.arguments.bundledir + "'"); } else { - cause = error.causeErrors; + this.updateStatus("Making remote bundle directory"); } - // Special case some known errors - if (cause !== undefined) { - if (cause.category === 1 && + const WARNING = 4; + const ALREADY_EXISTS = 19; + const EIGHT = 8; + const TARGET_DIR_NOT_EXIST = 93651005; + const NO_PERMISSION = -276865003; + try { + await Create.uss(zosMFSession, this.params.arguments.bundledir, "directory"); + } + catch (error) { + if (error.causeErrors !== undefined) + { + let cause; + if (typeof error.causeErrors !== "object") + { + try { + cause = JSON.parse(error.causeErrors); + } + catch (parseError) { + // whatever we received here it wasn't JSON. Oh well, never mind. + } + } + else { + cause = error.causeErrors; + } + + // Special case some known errors + if (cause !== undefined) { + if (cause.category === 1 && cause.rc === WARNING && cause.reason === ALREADY_EXISTS) { - // if it already exists, no worries - return; - } - if (cause.category === EIGHT && + // if it already exists, no worries + return; + } + if (cause.category === EIGHT && cause.rc === -1 && cause.reason === TARGET_DIR_NOT_EXIST) { - throw new Error("The target directory does not exist, consider creating it by issuing: \n" + + throw new Error("The target directory does not exist, consider creating it by issuing: \n" + "zowe zos-uss issue ssh \"mkdir -p " + this.params.arguments.targetdir + "\""); - } - if (cause.category === EIGHT && + } + if (cause.category === EIGHT && cause.rc === -1 && cause.reason === NO_PERMISSION) { - throw new Error("You are not authorized to create the target bundle directory '" + this.params.arguments.bundledir + "'."); - } - } - } - throw new Error("A problem occurred attempting to create directory '" + this.params.arguments.bundledir + "'. " + + throw new Error("You are not authorized to create the target bundle directory '" + this.params.arguments.bundledir + "'."); + } + } + } + throw new Error("A problem occurred attempting to create directory '" + this.params.arguments.bundledir + "'. " + "Problem is: " + error.message); + } } - } - - private async deleteBundleDirContents(sshSession: SshSession) { - this.updateStatus("Removing contents of remote bundle directory"); - await this.runSshCommandInRemoteDirectory(sshSession, this.params.arguments.bundledir, "if [ \"$(ls)\" ]; then rm -r *; fi"); - } - private async runSingleNpmInstall(sshSession: SshSession, remoteDirectory: string) { - if (this.params.arguments.verbose) { - this.updateStatus("Running 'npm install' in '" + remoteDirectory + "'"); - } - else { - this.updateStatus("Running 'npm install' in remote directory"); + private async deleteBundleDirContents(sshSession: SshSession) { + this.updateStatus("Removing contents of remote bundle directory"); + await this.runSshCommandInRemoteDirectory(sshSession, this.params.arguments.bundledir, "if [ \"$(ls)\" ]; then rm -r *; fi"); } - await this.runSshCommandInRemoteDirectory(sshSession, - remoteDirectory, - this.defaultRemoteNodehomeCmd + " && " + this.envSetupCommand + " && npm install"); - } + private async runSingleNpmInstall(sshSession: SshSession, remoteDirectory: string) { + if (this.params.arguments.verbose) { + this.updateStatus("Running 'npm install' in '" + remoteDirectory + "'"); + } + else { + this.updateStatus("Running 'npm install' in remote directory"); + } - private async runSingleNpmUninstall(sshSession: SshSession, remoteDirectory: string) { - if (this.params.arguments.verbose) { - this.updateStatus("Running 'npm uninstall *' in '" + remoteDirectory + "'"); - } - else { - this.updateStatus("Running 'npm uninstall *' in remote directory"); + await this.runSshCommandInRemoteDirectory(sshSession, + remoteDirectory, + this.defaultRemoteNodehomeCmd + " && " + this.envSetupCommand + " && npm install"); } - // uninstall each module individually - await this.runSshCommandInRemoteDirectory(sshSession, remoteDirectory, this.defaultRemoteNodehomeCmd + " && " + + private async runSingleNpmUninstall(sshSession: SshSession, remoteDirectory: string) { + if (this.params.arguments.verbose) { + this.updateStatus("Running 'npm uninstall *' in '" + remoteDirectory + "'"); + } + else { + this.updateStatus("Running 'npm uninstall *' in remote directory"); + } + + // uninstall each module individually + await this.runSshCommandInRemoteDirectory(sshSession, remoteDirectory, this.defaultRemoteNodehomeCmd + " && " + this.envSetupCommand + " && " + "if [ -d \"node_modules\" ] && [ \"$(ls node_modules)\" ]; then npm uninstall `ls -1 node_modules | tr '/\n' ' '`; fi"); - } - - private async runSshCommandInRemoteDirectory(sshSession: SshSession, directory: string, sshCommand: string) { - try { - if (this.params.arguments.verbose) { - this.updateStatus("Issuing SSH command '" + sshCommand + "' in remote directory '" + directory + "'"); - } - - this.sshOutputText = ""; - const sshReturnCode = await Shell.executeSshCwd(sshSession, sshCommand, directory, this.sshOutput.bind(this)); - const upperCaseOutputText = this.sshOutputText.toUpperCase(); - - // Note that FSUM9195 can imply that we've tried to delete the - // contents of an empty directory - that's not a problem. - // Check if FSUM9195 is the only FSUM error - let isOnlyFSUM9195 = false; - const countFSUM = (upperCaseOutputText.match(/FSUM/g) || []).length; - const countFSUM9195 = (upperCaseOutputText.match(/FSUM9195/g) || []).length; - if (countFSUM9195 !== 0 && + } + + private async runSshCommandInRemoteDirectory(sshSession: SshSession, directory: string, sshCommand: string) { + try { + if (this.params.arguments.verbose) { + this.updateStatus("Issuing SSH command '" + sshCommand + "' in remote directory '" + directory + "'"); + } + + this.sshOutputText = ""; + const sshReturnCode = await Shell.executeSshCwd(sshSession, sshCommand, directory, this.sshOutput.bind(this)); + const upperCaseOutputText = this.sshOutputText.toUpperCase(); + + // Note that FSUM9195 can imply that we've tried to delete the + // contents of an empty directory - that's not a problem. + // Check if FSUM9195 is the only FSUM error + let isOnlyFSUM9195 = false; + const countFSUM = (upperCaseOutputText.match(/FSUM/g) || []).length; + const countFSUM9195 = (upperCaseOutputText.match(/FSUM9195/g) || []).length; + if (countFSUM9195 !== 0 && countFSUM === countFSUM9195 && sshReturnCode === 1) { - isOnlyFSUM9195 = true; - } - - // Now check - // A. If exit code is non zero - // B. FSUM9195 is not the only FSUM error - if (sshReturnCode !== 0 && !isOnlyFSUM9195) { - // if we've not already logged the output, log it now - if (this.params.arguments.verbose !== true) { - this.params.response.console.log(Buffer.from(this.sshOutputText)); - } - throw new Error("The output from the remote command implied that an error occurred, return code " + sshReturnCode + "."); - } - } - catch (error) { - throw new Error("A problem occurred attempting to run '" + sshCommand + "' in remote directory '" + directory + + isOnlyFSUM9195 = true; + } + + // Now check + // A. If exit code is non zero + // B. FSUM9195 is not the only FSUM error + if (sshReturnCode !== 0 && !isOnlyFSUM9195) { + // if we've not already logged the output, log it now + if (this.params.arguments.verbose !== true) { + this.params.response.console.log(Buffer.from(this.sshOutputText)); + } + throw new Error("The output from the remote command implied that an error occurred, return code " + sshReturnCode + "."); + } + } + catch (error) { + throw new Error("A problem occurred attempting to run '" + sshCommand + "' in remote directory '" + directory + "'. Problem is: " + error.message); + } } - } - private async uploadBundle(zosMFSession: any) { - this.updateStatus("Uploading bundle contents to remote directory"); + private async uploadBundle(zosMFSession: any) { + this.updateStatus("Uploading bundle contents to remote directory"); - const uploadOptions: IUploadOptions = { recursive: true }; - uploadOptions.attributes = this.findZosAttributes(); - uploadOptions.task = new SubtaskWithStatus(this.progressBar, TaskProgress.TEN_PERCENT); + const uploadOptions: IUploadOptions = { recursive: true }; + uploadOptions.attributes = this.findZosAttributes(); + uploadOptions.task = new SubtaskWithStatus(this.progressBar, TaskProgress.TEN_PERCENT); - try { - await Upload.dirToUSSDirRecursive(zosMFSession, this.localDirectory, this.params.arguments.bundledir, uploadOptions); - } - catch (error) { - throw new Error("A problem occurred uploading the bundle contents to the remote directory '" + this.params.arguments.bundledir + + try { + await Upload.dirToUSSDirRecursive(zosMFSession, this.localDirectory, this.params.arguments.bundledir, uploadOptions); + } + catch (error) { + throw new Error("A problem occurred uploading the bundle contents to the remote directory '" + this.params.arguments.bundledir + "'. Problem is: " + error.message); + } } - } - - private findZosAttributes(): ZosFilesAttributes { - const attributesFileName = this.path.join(this.localDirectory, ".zosattributes"); - if (this.fs.existsSync(attributesFileName)) { - try { - const attributesFileContents = this.fs.readFileSync(attributesFileName).toString(); - return new ZosFilesAttributes(attributesFileContents, this.localDirectory); - } - catch (error) { - throw new Error("A problem occurred reading the local .zosattributes file '" + attributesFileName + + + private findZosAttributes(): ZosFilesAttributes { + const attributesFileName = this.path.join(this.localDirectory, ".zosattributes"); + if (this.fs.existsSync(attributesFileName)) { + try { + const attributesFileContents = this.fs.readFileSync(attributesFileName).toString(); + return new ZosFilesAttributes(attributesFileContents, this.localDirectory); + } + catch (error) { + throw new Error("A problem occurred reading the local .zosattributes file '" + attributesFileName + "'. Problem is: " + error.message); - } + } + } + + // A project specific .zosattributes has not been found, so use a default + this.issueWarning("No .zosattributes file found in the bundle directory, default values will be applied."); + return new ZosFilesAttributes(Bundle.getTemplateZosAttributesFile()); } - // A project specific .zosattributes has not been found, so use a default - this.issueWarning("No .zosattributes file found in the bundle directory, default values will be applied."); - return new ZosFilesAttributes(Bundle.getTemplateZosAttributesFile()); - } + // eslint-disable-next-line no-magic-numbers + private updateStatus(status: string, percentageIncrease = 3) { + const MAX_PROGRESS_BAR_MESSAGE = 60; + this.progressBar.percentComplete += percentageIncrease; + + if (status.length > MAX_PROGRESS_BAR_MESSAGE) + { + this.progressBar.statusMessage = status.substring(0, MAX_PROGRESS_BAR_MESSAGE) + "..."; + } + else { + this.progressBar.statusMessage = status; + } - private updateStatus(status: string, percentageIncrease = 3) { - const MAX_PROGRESS_BAR_MESSAGE = 60; - this.progressBar.percentComplete += percentageIncrease; + if (this.params.arguments.verbose) { + this.params.response.console.log(Buffer.from(status + "\n")); + } - if (status.length > MAX_PROGRESS_BAR_MESSAGE) - { - this.progressBar.statusMessage = status.substring(0, MAX_PROGRESS_BAR_MESSAGE) + "..."; + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(status); + } } - else { - this.progressBar.statusMessage = status; + + private startProgressBar() { + if (this.params.arguments.verbose !== true && this.progressBar !== undefined) { + this.params.response.progress.startBar({task: this.progressBar}); + } } - if (this.params.arguments.verbose) { - this.params.response.console.log(Buffer.from(status + "\n")); + private endProgressBar() { + if (this.params.arguments.verbose !== true && this.progressBar !== undefined) { + this.params.response.progress.endBar(); + } } - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(status); + private findAllPackageJSONDirs(directoryNameLocal: string, directoryNameRemote: string, found: string[]) { + // accumulate an array of all directories / sub-directories that contain a package.json file + const files = this.fs.readdirSync(directoryNameLocal); + for (const currentFile of files) { + const localFileName = this.path.join(directoryNameLocal, currentFile); + const remoteFileName = this.path.posix.join(directoryNameRemote, currentFile); + const stat = this.fs.lstatSync(localFileName); + + if (stat.isDirectory() && currentFile !== "node_modules") { + // If we've found a sub-directory, and it's not the special node_modules directory, scan it too. + this.findAllPackageJSONDirs(localFileName, remoteFileName, found); + } + else if (currentFile === "package.json") { + // The current directory has a package.json + found.push(directoryNameRemote); + } + } } - } - private startProgressBar() { - if (this.params.arguments.verbose !== true && this.progressBar !== undefined) { - this.params.response.progress.startBar({task: this.progressBar}); + private async runAllNpmInstalls(sshSession: SshSession, packageJsonFiles: string[]) { + for (const remoteDirectory of packageJsonFiles) { + await this.runSingleNpmInstall(sshSession, remoteDirectory); + } } - } - private endProgressBar() { - if (this.params.arguments.verbose !== true && this.progressBar !== undefined) { - this.params.response.progress.endBar(); + private async runAllNpmUninstalls(sshSession: SshSession, packageJsonFiles: string[]) { + for (const remoteDirectory of packageJsonFiles) { + await this.runSingleNpmUninstall(sshSession, remoteDirectory); + } } - } - private findAllPackageJSONDirs(directoryNameLocal: string, directoryNameRemote: string, found: string[]) { - // accumulate an array of all directories / sub-directories that contain a package.json file - const files = this.fs.readdirSync(directoryNameLocal); - for (const currentFile of files) { - const localFileName = this.path.join(directoryNameLocal, currentFile); - const remoteFileName = this.path.posix.join(directoryNameRemote, currentFile); - const stat = this.fs.lstatSync(localFileName); - - if (stat.isDirectory() && currentFile !== "node_modules") { - // If we've found a sub-directory, and it's not the special node_modules directory, scan it too. - this.findAllPackageJSONDirs(localFileName, remoteFileName, found); - } - else if (currentFile === "package.json") { - // The current directory has a package.json - found.push(directoryNameRemote); - } - } - } - - private async runAllNpmInstalls(sshSession: SshSession, packageJsonFiles: string[]) { - for (const remoteDirectory of packageJsonFiles) { - await this.runSingleNpmInstall(sshSession, remoteDirectory); - } - } - - private async runAllNpmUninstalls(sshSession: SshSession, packageJsonFiles: string[]) { - for (const remoteDirectory of packageJsonFiles) { - await this.runSingleNpmUninstall(sshSession, remoteDirectory); - } - } - - private async generateGeneralDiagnostics(cicsSession: AbstractSession): Promise { - let msgBuffer = ""; - try { - if (cicsSession !== undefined) { - // Attempt to gather additional Node.js specific information from CICS - this.updateStatus("Gathering scope information"); - msgBuffer = await this.gatherGeneralDiagnosticsFromCics(cicsSession); - } - } - catch (diagnosticsError) { - // Something went wrong generating scope info. Don't trouble the user - // with what might be an exotic error message (e.g. hex dump of an entire HTML page), - // just log the failure. - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(diagnosticsError.message); - } - } - - // Something went wrong, suggest a command that can be run to figure out more. - if (msgBuffer === "") { - this.issueMessage("An attempt to query the remote CICSplex using the cics plug-in has failed.\n"); - } - - return msgBuffer; - } - - private async generateNodejsSpecificDiagnostics(cicsSession: AbstractSession): Promise { - let msgBuffer = ""; - - if (cicsSession === undefined) { - return msgBuffer; - } - - try { - // Attempt to gather additional Node.js specific information from CICS - this.updateStatus("Gathering Node.js diagnostics"); - msgBuffer = await this.gatherNodejsDiagnosticsFromCics(cicsSession); - } - catch (diagnosticsError) { - // Something went wrong generating diagnostic info. Don't trouble the user - // with what might be an exotic error message (e.g. hex dump of an entire HTML page), - // just log the failure. - if (this.params.arguments.silent === undefined) { - const logger = Logger.getAppLogger(); - logger.debug(diagnosticsError.message); - } - } - - // We must have a cics profile in order to have got this far, so suggest a command that can be run to figure out more. - if (msgBuffer === "") { - msgBuffer += "For further information on the state of your NODEJSAPP resources, consider running the following command:\n\n" + + private async generateGeneralDiagnostics(cicsSession: AbstractSession): Promise { + let msgBuffer = ""; + try { + if (cicsSession !== undefined) { + // Attempt to gather additional Node.js specific information from CICS + this.updateStatus("Gathering scope information"); + msgBuffer = await this.gatherGeneralDiagnosticsFromCics(cicsSession); + } + } + catch (diagnosticsError) { + // Something went wrong generating scope info. Don't trouble the user + // with what might be an exotic error message (e.g. hex dump of an entire HTML page), + // just log the failure. + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(diagnosticsError.message); + } + } + + // Something went wrong, suggest a command that can be run to figure out more. + if (msgBuffer === "") { + this.issueMessage("An attempt to query the remote CICSplex using the cics plug-in has failed.\n"); + } + + return msgBuffer; + } + + private async generateNodejsSpecificDiagnostics(cicsSession: AbstractSession): Promise { + let msgBuffer = ""; + + if (cicsSession === undefined) { + return msgBuffer; + } + + try { + // Attempt to gather additional Node.js specific information from CICS + this.updateStatus("Gathering Node.js diagnostics"); + msgBuffer = await this.gatherNodejsDiagnosticsFromCics(cicsSession); + } + catch (diagnosticsError) { + // Something went wrong generating diagnostic info. Don't trouble the user + // with what might be an exotic error message (e.g. hex dump of an entire HTML page), + // just log the failure. + if (this.params.arguments.silent === undefined) { + const logger = Logger.getAppLogger(); + logger.debug(diagnosticsError.message); + } + } + + // We must have a cics profile in order to have got this far, so suggest a command that can be run to figure out more. + if (msgBuffer === "") { + msgBuffer += "For further information on the state of your NODEJSAPP resources, consider running the following command:\n\n" + "zowe cics get resource CICSNodejsapp --region-name " + this.params.arguments.scope + " --criteria \"BUNDLE=" + this.params.arguments.name + "\" --cics-plex " + this.params.arguments.cicsplex + "\n\n"; - } + } - return msgBuffer; - } + return msgBuffer; + } - private async gatherGeneralDiagnosticsFromCics(cicsSession: AbstractSession): Promise { + private async gatherGeneralDiagnosticsFromCics(cicsSession: AbstractSession): Promise { // Issue a CMCI get to the target CICSplex - try { - this.updateStatus("Querying regions in scope over CMCI"); - const regionData: IResourceParms = { name: "CICSRegion", - regionName: this.params.arguments.scope, - cicsPlex: this.params.arguments.cicsplex }; - const cmciRegionResponse = await getResource(cicsSession, regionData); - if (cmciRegionResponse === undefined || + try { + this.updateStatus("Querying regions in scope over CMCI"); + const regionData: IResourceParms = { name: "CICSRegion", + regionName: this.params.arguments.scope, + cicsPlex: this.params.arguments.cicsplex }; + const cmciRegionResponse = await getResource(cicsSession, regionData); + if (cmciRegionResponse === undefined || cmciRegionResponse.response === undefined || cmciRegionResponse.response.records === undefined || cmciRegionResponse.response.records.cicsregion === undefined) { - throw new Error("CICSRegion CMCI output record not found."); - } - const outputRegionRecords = cmciRegionResponse.response.records.cicsregion; - let msgBuffer = "Regions in scope '" + this.params.arguments.scope + "' of CICSplex '" + this.params.arguments.cicsplex + "':\n"; - - // We may have an array of records if there was more than one Region in the scope - if (Array.isArray(outputRegionRecords)) { - for (const record of outputRegionRecords) { - msgBuffer = this.reportRegionData(record, msgBuffer); - } - } - else { - msgBuffer = this.reportRegionData(outputRegionRecords, msgBuffer); - } - return msgBuffer; - } - catch (error) { - throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message); - } - } - - private async gatherNodejsDiagnosticsFromCics(cicsSession: AbstractSession): Promise { - try { - // Process each NODEJSAPP in the Scope - this.updateStatus("Querying NODEJSAPP resources over CMCI"); - const nodejsData: IResourceParms = { name: "CICSNodejsapp", - criteria: "BUNDLE=" + this.params.arguments.name, - regionName: this.params.arguments.scope, - cicsPlex: this.params.arguments.cicsplex }; - const cmciNodejsResponse = await getResource(cicsSession, nodejsData); - if (cmciNodejsResponse === undefined || + throw new Error("CICSRegion CMCI output record not found."); + } + const outputRegionRecords = cmciRegionResponse.response.records.cicsregion; + let msgBuffer = "Regions in scope '" + this.params.arguments.scope + "' of CICSplex '" + this.params.arguments.cicsplex + "':\n"; + + // We may have an array of records if there was more than one Region in the scope + if (Array.isArray(outputRegionRecords)) { + for (const record of outputRegionRecords) { + msgBuffer = this.reportRegionData(record, msgBuffer); + } + } + else { + msgBuffer = this.reportRegionData(outputRegionRecords, msgBuffer); + } + return msgBuffer; + } + catch (error) { + throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message); + } + } + + private async gatherNodejsDiagnosticsFromCics(cicsSession: AbstractSession): Promise { + try { + // Process each NODEJSAPP in the Scope + this.updateStatus("Querying NODEJSAPP resources over CMCI"); + const nodejsData: IResourceParms = { name: "CICSNodejsapp", + criteria: "BUNDLE=" + this.params.arguments.name, + regionName: this.params.arguments.scope, + cicsPlex: this.params.arguments.cicsplex }; + const cmciNodejsResponse = await getResource(cicsSession, nodejsData); + if (cmciNodejsResponse === undefined || cmciNodejsResponse.response === undefined || cmciNodejsResponse.response.records === undefined || cmciNodejsResponse.response.records.cicsnodejsapp === undefined) { - throw new Error("CICSNodejsapp CMCI output record not found."); - } - const outputNodejsRecords = cmciNodejsResponse.response.records.cicsnodejsapp; - - let msgBuffer = "\nNODEJSAPP resources for bundle '" + this.params.arguments.name + "' in scope '" + this.params.arguments.scope + "':\n"; - - // We may have an array of records if there was more than one NODEJSAPP in the bundle - if (Array.isArray(outputNodejsRecords)) { - for (const record of outputNodejsRecords) { - msgBuffer = this.reportNODEJSAPPData(record, msgBuffer); + throw new Error("CICSNodejsapp CMCI output record not found."); + } + const outputNodejsRecords = cmciNodejsResponse.response.records.cicsnodejsapp; + + let msgBuffer = "\nNODEJSAPP resources for bundle '" + this.params.arguments.name + "' in scope '" + this.params.arguments.scope + "':\n"; + + // We may have an array of records if there was more than one NODEJSAPP in the bundle + if (Array.isArray(outputNodejsRecords)) { + for (const record of outputNodejsRecords) { + msgBuffer = this.reportNODEJSAPPData(record, msgBuffer); + } + } + else { + msgBuffer = this.reportNODEJSAPPData(outputNodejsRecords, msgBuffer); + } + return msgBuffer; + } + catch (error) { + throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message); } - } - else { - msgBuffer = this.reportNODEJSAPPData(outputNodejsRecords, msgBuffer); - } - return msgBuffer; - } - catch (error) { - throw new Error("Failure collecting diagnostics for Bundle " + this.params.arguments.name + ": " + error.message); } - } - private reportRegionData(outputRecord: any, msgBuffer: string): string { - const MAX_LENGTH = 8; - const applid = outputRecord.applid.padEnd(MAX_LENGTH, " "); - const jobid = outputRecord.jobid.padEnd(MAX_LENGTH, " "); - const jobname = outputRecord.jobname.padEnd(MAX_LENGTH, " "); - const sysname = outputRecord.mvssysname.padEnd(MAX_LENGTH, " "); + private reportRegionData(outputRecord: any, msgBuffer: string): string { + const MAX_LENGTH = 8; + const applid = outputRecord.applid.padEnd(MAX_LENGTH, " "); + const jobid = outputRecord.jobid.padEnd(MAX_LENGTH, " "); + const jobname = outputRecord.jobname.padEnd(MAX_LENGTH, " "); + const sysname = outputRecord.mvssysname.padEnd(MAX_LENGTH, " "); - return msgBuffer + " Applid: " + applid + " jobname: " + jobname + " jobid: " + jobid + " sysname: " + sysname + "\n"; - } + return msgBuffer + " Applid: " + applid + " jobname: " + jobname + " jobid: " + jobid + " sysname: " + sysname + "\n"; + } - private reportNODEJSAPPData(outputRecord: any, msgBuffer: string) { - const name = outputRecord.name; - const enablestatus = outputRecord.enablestatus; - const pid = outputRecord.pid; - const region = outputRecord.eyu_cicsname; - let stdout = outputRecord.stdout; - let stderr = outputRecord.stderr; + private reportNODEJSAPPData(outputRecord: any, msgBuffer: string) { + const name = outputRecord.name; + const enablestatus = outputRecord.enablestatus; + const pid = outputRecord.pid; + const region = outputRecord.eyu_cicsname; + let stdout = outputRecord.stdout; + let stderr = outputRecord.stderr; - if (stdout === undefined || stdout.trim() === "") { - stdout = ""; - } - if (stderr === undefined || stderr.trim() === "") { - stderr = ""; - } + if (stdout === undefined || stdout.trim() === "") { + stdout = ""; + } + if (stderr === undefined || stderr.trim() === "") { + stderr = ""; + } - return msgBuffer + "NODEJSAPP resource '" + name + "' is in '" + enablestatus + "' state in region '" + + return msgBuffer + "NODEJSAPP resource '" + name + "' is in '" + enablestatus + "' state in region '" + region + "' with process id '" + pid + "'.\n" + " stdout: " + stdout + "\n" + " stderr: " + stderr + "\n"; - } + } } diff --git a/src/api/BundlePush/CmciConfig.ts b/src/api/BundlePush/CmciConfig.ts index 15664abf..071dc5b0 100644 --- a/src/api/BundlePush/CmciConfig.ts +++ b/src/api/BundlePush/CmciConfig.ts @@ -22,67 +22,68 @@ import { IHandlerParameters, IProfile } from "@zowe/imperative"; */ export class CmciConfig { - /** + /** * Merge command line overrides together with the optional cmciProfile into a * composite whole */ - public static mergeProfile(cmciProfile: IProfile, params: IHandlerParameters) { - - if (params.arguments.ch !== undefined) { - cmciProfile.host = params.arguments.ch; - cmciProfile.H = params.arguments.ch; - } - - if (params.arguments.cpo !== undefined) { - cmciProfile.port = params.arguments.cpo; - cmciProfile.P = params.arguments.cpo; + public static mergeProfile(cmciProfile: IProfile, params: IHandlerParameters) { + + if (params.arguments.ch !== undefined) { + cmciProfile.host = params.arguments.ch; + cmciProfile.H = params.arguments.ch; + } + + if (params.arguments.cpo !== undefined) { + cmciProfile.port = params.arguments.cpo; + cmciProfile.P = params.arguments.cpo; + } + + if (params.arguments.cu !== undefined) { + cmciProfile.user = params.arguments.cu; + cmciProfile.u = params.arguments.cu; + } + + if (params.arguments.cpw !== undefined) { + cmciProfile.password = params.arguments.cpw; + cmciProfile.pw = params.arguments.cpw; + } + + if (params.arguments.cru !== undefined) { + cmciProfile.rejectUnauthorized = params.arguments.cru; + cmciProfile.ru = params.arguments.cru; + } + + if (params.arguments.cpr !== undefined) { + cmciProfile.protocol = params.arguments.cpr; + cmciProfile.o = params.arguments.cpr; + } + + // The CICS profile is optional, only validate it further if there is some content + if (Object.keys(cmciProfile).length > 0) { + CmciConfig.validateRequired(cmciProfile); + } } - if (params.arguments.cu !== undefined) { - cmciProfile.user = params.arguments.cu; - cmciProfile.u = params.arguments.cu; - } + // eslint-disable-next-line no-magic-numbers + private static DEFAULT_CMCI_PORT = 1490; + private static validateRequired(cmciProfile: IProfile) { + this.checkValueFound(cmciProfile.host, "cics-host"); + this.checkValueFound(cmciProfile.user, "cics-user"); + this.checkValueFound(cmciProfile.password, "cics-password"); - if (params.arguments.cpw !== undefined) { - cmciProfile.password = params.arguments.cpw; - cmciProfile.pw = params.arguments.cpw; - } - - if (params.arguments.cru !== undefined) { - cmciProfile.rejectUnauthorized = params.arguments.cru; - cmciProfile.ru = params.arguments.cru; - } - - if (params.arguments.cpr !== undefined) { - cmciProfile.protocol = params.arguments.cpr; - cmciProfile.o = params.arguments.cpr; - } - - // The CICS profile is optional, only validate it further if there is some content - if (Object.keys(cmciProfile).length > 0) { - CmciConfig.validateRequired(cmciProfile); - } - } - - private static DEFAULT_CMCI_PORT = 1490; - private static validateRequired(cmciProfile: IProfile) { - this.checkValueFound(cmciProfile.host, "cics-host"); - this.checkValueFound(cmciProfile.user, "cics-user"); - this.checkValueFound(cmciProfile.password, "cics-password"); - - // Now implement the default value for the port - if (cmciProfile.port === undefined) { - cmciProfile.port = CmciConfig.DEFAULT_CMCI_PORT; - cmciProfile.P = CmciConfig.DEFAULT_CMCI_PORT; - } + // Now implement the default value for the port + if (cmciProfile.port === undefined) { + cmciProfile.port = CmciConfig.DEFAULT_CMCI_PORT; + cmciProfile.P = CmciConfig.DEFAULT_CMCI_PORT; + } // Note, default values for protocol and rejectUnauthorized are implemented // in the underlying cics-plugin. - } + } - private static checkValueFound(value: string, parm: string) { - if (value === undefined) { - throw new Error("Partial cics plug-in configuration encountered, --" + parm + " is not set."); + private static checkValueFound(value: string, parm: string) { + if (value === undefined) { + throw new Error("Partial cics plug-in configuration encountered, --" + parm + " is not set."); + } } - } } diff --git a/src/api/BundlePush/SshConfig.ts b/src/api/BundlePush/SshConfig.ts index 534cdb23..20b6c799 100644 --- a/src/api/BundlePush/SshConfig.ts +++ b/src/api/BundlePush/SshConfig.ts @@ -22,69 +22,70 @@ import { IHandlerParameters, IProfile } from "@zowe/imperative"; */ export class SshConfig { - /** + /** * Merge command line overrides together with the optional sshProfile into a * composite whole */ - public static mergeProfile(sshProfile: IProfile, params: IHandlerParameters) { - - if (params.arguments.sh !== undefined) { - sshProfile.host = params.arguments.sh; - sshProfile.H = params.arguments.sh; - } - - if (params.arguments.sp !== undefined) { - sshProfile.port = params.arguments.sp; - sshProfile.P = params.arguments.sp; - } - - if (params.arguments.su !== undefined) { - sshProfile.user = params.arguments.su; - sshProfile.u = params.arguments.su; - } - - if (params.arguments.spw !== undefined) { - sshProfile.password = params.arguments.spw; - sshProfile.pass = params.arguments.spw; - sshProfile.pw = params.arguments.spw; + public static mergeProfile(sshProfile: IProfile, params: IHandlerParameters) { + + if (params.arguments.sh !== undefined) { + sshProfile.host = params.arguments.sh; + sshProfile.H = params.arguments.sh; + } + + if (params.arguments.sp !== undefined) { + sshProfile.port = params.arguments.sp; + sshProfile.P = params.arguments.sp; + } + + if (params.arguments.su !== undefined) { + sshProfile.user = params.arguments.su; + sshProfile.u = params.arguments.su; + } + + if (params.arguments.spw !== undefined) { + sshProfile.password = params.arguments.spw; + sshProfile.pass = params.arguments.spw; + sshProfile.pw = params.arguments.spw; + } + + if (params.arguments.spk !== undefined) { + sshProfile.privateKey = params.arguments.spk; + sshProfile.key = params.arguments.spk; + sshProfile.pk = params.arguments.spk; + } + + if (params.arguments.skp !== undefined) { + sshProfile.keyPassphrase = params.arguments.skp; + sshProfile.passphrase = params.arguments.skp; + sshProfile.kp = params.arguments.skp; + } + + if (params.arguments.sht !== undefined) { + sshProfile.handshakeTimeout = params.arguments.sht; + sshProfile.timeout = params.arguments.sht; + sshProfile.to = params.arguments.sht; + } + + SshConfig.validateRequired(sshProfile); } - if (params.arguments.spk !== undefined) { - sshProfile.privateKey = params.arguments.spk; - sshProfile.key = params.arguments.spk; - sshProfile.pk = params.arguments.spk; - } - - if (params.arguments.skp !== undefined) { - sshProfile.keyPassphrase = params.arguments.skp; - sshProfile.passphrase = params.arguments.skp; - sshProfile.kp = params.arguments.skp; - } - - if (params.arguments.sht !== undefined) { - sshProfile.handshakeTimeout = params.arguments.sht; - sshProfile.timeout = params.arguments.sht; - sshProfile.to = params.arguments.sht; - } - - SshConfig.validateRequired(sshProfile); - } - - private static DEFAULT_SSH_PORT = 22; - private static validateRequired(sshProfile: IProfile) { - this.checkValueFound(sshProfile.host, "ssh-host"); - this.checkValueFound(sshProfile.user, "ssh-user"); - - // Now implement the default value for the port - if (sshProfile.port === undefined) { - sshProfile.port = SshConfig.DEFAULT_SSH_PORT; - sshProfile.P = SshConfig.DEFAULT_SSH_PORT; + // eslint-disable-next-line no-magic-numbers + private static DEFAULT_SSH_PORT = 22; + private static validateRequired(sshProfile: IProfile) { + this.checkValueFound(sshProfile.host, "ssh-host"); + this.checkValueFound(sshProfile.user, "ssh-user"); + + // Now implement the default value for the port + if (sshProfile.port === undefined) { + sshProfile.port = SshConfig.DEFAULT_SSH_PORT; + sshProfile.P = SshConfig.DEFAULT_SSH_PORT; + } } - } - private static checkValueFound(value: string, parm: string) { - if (value === undefined) { - throw new Error("Required parameter --" + parm + " is not set."); + private static checkValueFound(value: string, parm: string) { + if (value === undefined) { + throw new Error("Required parameter --" + parm + " is not set."); + } } - } } diff --git a/src/api/BundlePush/ZosmfConfig.ts b/src/api/BundlePush/ZosmfConfig.ts index 09b84fb6..82e9db92 100644 --- a/src/api/BundlePush/ZosmfConfig.ts +++ b/src/api/BundlePush/ZosmfConfig.ts @@ -22,68 +22,69 @@ import { IHandlerParameters, IProfile } from "@zowe/imperative"; */ export class ZosmfConfig { - /** + /** * Merge command line overrides together with the optional zosmfProfile into a * composite whole */ - public static mergeProfile(zosmfProfile: IProfile, params: IHandlerParameters) { - - if (params.arguments.zh !== undefined) { - zosmfProfile.host = params.arguments.zh; - zosmfProfile.H = params.arguments.zh; - } - - if (params.arguments.zp !== undefined) { - zosmfProfile.port = params.arguments.zp; - zosmfProfile.P = params.arguments.zp; - } - - if (params.arguments.zu !== undefined) { - zosmfProfile.user = params.arguments.zu; - zosmfProfile.u = params.arguments.zu; - } - - if (params.arguments.zpw !== undefined) { - zosmfProfile.password = params.arguments.zpw; - zosmfProfile.pass = params.arguments.zpw; - zosmfProfile.pw = params.arguments.zpw; - } - - if (params.arguments.zru !== undefined) { - zosmfProfile.rejectUnauthorized = params.arguments.zru; - zosmfProfile.ru = params.arguments.zru; - } - - if (params.arguments.zbp !== undefined) { - zosmfProfile.basePath = params.arguments.zbp; - zosmfProfile.bp = params.arguments.zbp; - } - - ZosmfConfig.validateRequired(zosmfProfile); - } - - private static DEFAULT_ZOSMF_PORT = 443; - private static validateRequired(zosmfProfile: IProfile) { - this.checkValueFound(zosmfProfile.host, "zosmf-host"); - this.checkValueFound(zosmfProfile.user, "zosmf-user"); - this.checkValueFound(zosmfProfile.password, "zosmf-password"); - - // Now implement the default value for the port - if (zosmfProfile.port === undefined) { - zosmfProfile.port = ZosmfConfig.DEFAULT_ZOSMF_PORT; - zosmfProfile.P = ZosmfConfig.DEFAULT_ZOSMF_PORT; + public static mergeProfile(zosmfProfile: IProfile, params: IHandlerParameters) { + + if (params.arguments.zh !== undefined) { + zosmfProfile.host = params.arguments.zh; + zosmfProfile.H = params.arguments.zh; + } + + if (params.arguments.zp !== undefined) { + zosmfProfile.port = params.arguments.zp; + zosmfProfile.P = params.arguments.zp; + } + + if (params.arguments.zu !== undefined) { + zosmfProfile.user = params.arguments.zu; + zosmfProfile.u = params.arguments.zu; + } + + if (params.arguments.zpw !== undefined) { + zosmfProfile.password = params.arguments.zpw; + zosmfProfile.pass = params.arguments.zpw; + zosmfProfile.pw = params.arguments.zpw; + } + + if (params.arguments.zru !== undefined) { + zosmfProfile.rejectUnauthorized = params.arguments.zru; + zosmfProfile.ru = params.arguments.zru; + } + + if (params.arguments.zbp !== undefined) { + zosmfProfile.basePath = params.arguments.zbp; + zosmfProfile.bp = params.arguments.zbp; + } + + ZosmfConfig.validateRequired(zosmfProfile); } - // And for reject-unauthorized - if (zosmfProfile.rejectUnauthorized === undefined) { - zosmfProfile.rejectUnauthorized = true; - zosmfProfile.ru = true; + // eslint-disable-next-line no-magic-numbers + private static DEFAULT_ZOSMF_PORT = 443; + private static validateRequired(zosmfProfile: IProfile) { + this.checkValueFound(zosmfProfile.host, "zosmf-host"); + this.checkValueFound(zosmfProfile.user, "zosmf-user"); + this.checkValueFound(zosmfProfile.password, "zosmf-password"); + + // Now implement the default value for the port + if (zosmfProfile.port === undefined) { + zosmfProfile.port = ZosmfConfig.DEFAULT_ZOSMF_PORT; + zosmfProfile.P = ZosmfConfig.DEFAULT_ZOSMF_PORT; + } + + // And for reject-unauthorized + if (zosmfProfile.rejectUnauthorized === undefined) { + zosmfProfile.rejectUnauthorized = true; + zosmfProfile.ru = true; + } } - } - private static checkValueFound(value: string, parm: string) { - if (value === undefined) { - throw new Error("Required parameter --" + parm + " is not set."); + private static checkValueFound(value: string, parm: string) { + if (value === undefined) { + throw new Error("Required parameter --" + parm + " is not set."); + } } - } } diff --git a/src/cli/deploy/bundle/DeployBundle.definition.ts b/src/cli/deploy/bundle/DeployBundle.definition.ts index 8f8c2b65..08803bf7 100644 --- a/src/cli/deploy/bundle/DeployBundle.definition.ts +++ b/src/cli/deploy/bundle/DeployBundle.definition.ts @@ -40,8 +40,8 @@ export const DeployBundleDefinition: ICommandDefinition = { type: "command", handler: __dirname + "/DeployBundle.handler", options: [ NameOption, BundledirOption, CicsplexOption, ScopeOption, CsdgroupOption , ResgroupOption, - CicshlqOption, CpsmhlqOption, DescriptionOption, JobcardOption, TimeoutOption, TargetStateOption, VerboseOption] - .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS), + CicshlqOption, CpsmhlqOption, DescriptionOption, JobcardOption, TimeoutOption, TargetStateOption, VerboseOption] + .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS), profile: { optional: ["cics-deploy", "zosmf"] }, examples: [ { diff --git a/src/cli/deploy/bundle/DeployBundle.handler.ts b/src/cli/deploy/bundle/DeployBundle.handler.ts index a2d8b5cd..c160e921 100644 --- a/src/cli/deploy/bundle/DeployBundle.handler.ts +++ b/src/cli/deploy/bundle/DeployBundle.handler.ts @@ -33,8 +33,8 @@ export default class DeployBundleHandler extends BundleParentHandler implements */ public async performAction(params: IHandlerParameters): Promise { - const bdep = new BundleDeployer(params); - const msg = await bdep.deployBundle(); - return msg; + const bdep = new BundleDeployer(params); + const msg = await bdep.deployBundle(); + return msg; } } diff --git a/src/cli/deploy/bundle/options/TargetState.option.ts b/src/cli/deploy/bundle/options/TargetState.option.ts index 68cf352c..1fb8234c 100644 --- a/src/cli/deploy/bundle/options/TargetState.option.ts +++ b/src/cli/deploy/bundle/options/TargetState.option.ts @@ -22,8 +22,8 @@ export const TargetStateOption: ICommandOptionDefinition = { required: false, defaultValue: "ENABLED", allowableValues: { - values: ["DISABLED", "ENABLED", "AVAILABLE"], - caseSensitive: false + values: ["DISABLED", "ENABLED", "AVAILABLE"], + caseSensitive: false }, group: "cics-deploy Options", description: "Specifies the target state for the deployed bundle." diff --git a/src/cli/generate/bundle/GenerateBundle.definition.ts b/src/cli/generate/bundle/GenerateBundle.definition.ts index 21136231..cb4deed7 100644 --- a/src/cli/generate/bundle/GenerateBundle.definition.ts +++ b/src/cli/generate/bundle/GenerateBundle.definition.ts @@ -33,7 +33,7 @@ export const GenerateBundleDefinition: ICommandDefinition = { type: "command", handler: __dirname + "/GenerateBundle.handler", options: [ BundleidOption, BundleversionOption, NodejsappOption, StartscriptOption, PortOption, - OverwriteOption, MergeOption ], + OverwriteOption, MergeOption ], examples: [ { description: "Generate a CICS bundle in the working directory, taking information from package.json", diff --git a/src/cli/generate/bundle/GenerateBundle.handler.ts b/src/cli/generate/bundle/GenerateBundle.handler.ts index ae28b86c..da5599f9 100644 --- a/src/cli/generate/bundle/GenerateBundle.handler.ts +++ b/src/cli/generate/bundle/GenerateBundle.handler.ts @@ -32,19 +32,19 @@ export default class GenerateBundleHandler extends BundleParentHandler implement * @memberof DeployBundleHandler */ public async performAction(params: IHandlerParameters): Promise { - const autobundler = new AutoBundler(process.cwd(), params); - if (params.arguments.nosave !== "true") { - autobundler.save(); - } + const autobundler = new AutoBundler(process.cwd(), params); + if (params.arguments.nosave !== "true") { + autobundler.save(); + } - // Create a response message - let msg; - if (autobundler.getBundle().getId() === undefined) { - msg = "Anonymous CICS Bundle generated"; - } - else { - msg = 'CICS Bundle generated with bundleid "' + autobundler.getBundle().getId() + '"'; - } - return msg; + // Create a response message + let msg; + if (autobundler.getBundle().getId() === undefined) { + msg = "Anonymous CICS Bundle generated"; + } + else { + msg = 'CICS Bundle generated with bundleid "' + autobundler.getBundle().getId() + '"'; + } + return msg; } } diff --git a/src/cli/push/bundle/PushBundle.definition.ts b/src/cli/push/bundle/PushBundle.definition.ts index 5c6e67cf..6b1ab56b 100644 --- a/src/cli/push/bundle/PushBundle.definition.ts +++ b/src/cli/push/bundle/PushBundle.definition.ts @@ -40,11 +40,11 @@ export const PushBundleDefinition: ICommandDefinition = { type: "command", handler: __dirname + "/PushBundle.handler", options: [ NameOption, TargetdirOption, CicsplexOption, ScopeOption, CsdgroupOption , ResgroupOption, - CicshlqOption, CpsmhlqOption, DescriptionOption, JobcardOption, TimeoutOption, TargetStateOption, - VerboseOption, OverwriteOption ] - .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS) - .concat(SshOptions.CICS_DEPLOY_SSH_CONNECTION_OPTIONS) - .concat(CmciOptions.CICS_DEPLOY_CMCI_CONNECTION_OPTIONS), + CicshlqOption, CpsmhlqOption, DescriptionOption, JobcardOption, TimeoutOption, TargetStateOption, + VerboseOption, OverwriteOption ] + .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS) + .concat(SshOptions.CICS_DEPLOY_SSH_CONNECTION_OPTIONS) + .concat(CmciOptions.CICS_DEPLOY_CMCI_CONNECTION_OPTIONS), profile: { optional: ["cics-deploy", "zosmf", "ssh", "cics"] }, examples: [ { diff --git a/src/cli/push/bundle/PushBundle.handler.ts b/src/cli/push/bundle/PushBundle.handler.ts index 6d63f79b..98d89a7c 100644 --- a/src/cli/push/bundle/PushBundle.handler.ts +++ b/src/cli/push/bundle/PushBundle.handler.ts @@ -33,7 +33,7 @@ export default class PushBundleHandler extends BundleParentHandler implements IC */ public async performAction(params: IHandlerParameters): Promise { - const pusher = await new BundlePusher(params, process.cwd()); - return pusher.performPush(); + const pusher = await new BundlePusher(params, process.cwd()); + return pusher.performPush(); } } diff --git a/src/cli/push/bundle/options/CmciOptions.ts b/src/cli/push/bundle/options/CmciOptions.ts index 1669c24d..29ad59cd 100644 --- a/src/cli/push/bundle/options/CmciOptions.ts +++ b/src/cli/push/bundle/options/CmciOptions.ts @@ -15,54 +15,54 @@ import { ICommandOptionDefinition } from "@zowe/imperative"; * scmci command line options, derived from zowe-cics equivalents */ export class CmciOptions { - public static GROUP = "CICS Connection Options"; + public static GROUP = "CICS Connection Options"; - public static CICS_DEPLOY_CMCI_OPTION_HOST: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_HOST: ICommandOptionDefinition = { name: "cics-host", aliases: ["ch"], description: "The CMCI server host name.", type: "string", required: false, group: CmciOptions.GROUP - }; + }; - public static CICS_DEPLOY_CMCI_OPTION_PORT: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_PORT: ICommandOptionDefinition = { name: "cics-port", aliases: ["cpo"], description: "The CICS server port.", type: "number", required: false, group: CmciOptions.GROUP - }; + }; - public static CICS_DEPLOY_CMCI_OPTION_USER: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_USER: ICommandOptionDefinition = { name: "cics-user", aliases: ["cu"], description: "Mainframe (CICS) user name, which can be the same as your TSO login.", type: "string", required: false, group: CmciOptions.GROUP - }; + }; - public static CICS_DEPLOY_CMCI_OPTION_PASSWORD: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_PASSWORD: ICommandOptionDefinition = { name: "cics-password", aliases: ["cpw"], description: "Mainframe (CICS) password, which can be the same as your TSO password.", type: "string", required: false, group: CmciOptions.GROUP - }; + }; - public static CICS_DEPLOY_CMCI_OPTION_REJECT_UNAUTHORIZED: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_REJECT_UNAUTHORIZED: ICommandOptionDefinition = { name: "cics-reject-unauthorized", aliases: ["cru"], description: "Reject self-signed certificates.", type: "boolean", required: false, group: CmciOptions.GROUP - }; + }; - public static CICS_DEPLOY_CMCI_OPTION_PROTOCOL: ICommandOptionDefinition = { + public static CICS_DEPLOY_CMCI_OPTION_PROTOCOL: ICommandOptionDefinition = { name: "cics-protocol", aliases: ["cpr"], description: "Specifies CMCI protocol (http or https).", @@ -70,19 +70,19 @@ export class CmciOptions { required: false, allowableValues: {values: ["http", "https"], caseSensitive: false}, group: CmciOptions.GROUP - }; + }; - /** + /** * Options related to connecting to CMCI */ - public static CICS_DEPLOY_CMCI_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ - CmciOptions.CICS_DEPLOY_CMCI_OPTION_HOST, - CmciOptions.CICS_DEPLOY_CMCI_OPTION_PORT, - CmciOptions.CICS_DEPLOY_CMCI_OPTION_USER, - CmciOptions.CICS_DEPLOY_CMCI_OPTION_PASSWORD, - CmciOptions.CICS_DEPLOY_CMCI_OPTION_REJECT_UNAUTHORIZED, - CmciOptions.CICS_DEPLOY_CMCI_OPTION_PROTOCOL - ]; + public static CICS_DEPLOY_CMCI_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ + CmciOptions.CICS_DEPLOY_CMCI_OPTION_HOST, + CmciOptions.CICS_DEPLOY_CMCI_OPTION_PORT, + CmciOptions.CICS_DEPLOY_CMCI_OPTION_USER, + CmciOptions.CICS_DEPLOY_CMCI_OPTION_PASSWORD, + CmciOptions.CICS_DEPLOY_CMCI_OPTION_REJECT_UNAUTHORIZED, + CmciOptions.CICS_DEPLOY_CMCI_OPTION_PROTOCOL + ]; } diff --git a/src/cli/push/bundle/options/SshOptions.ts b/src/cli/push/bundle/options/SshOptions.ts index 9f855e17..e17b569b 100644 --- a/src/cli/push/bundle/options/SshOptions.ts +++ b/src/cli/push/bundle/options/SshOptions.ts @@ -17,79 +17,79 @@ import { SshSession } from "@zowe/cli"; */ export class SshOptions { - public static CICS_DEPLOY_SSH_OPTION_HOST: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_HOST: ICommandOptionDefinition = { name: "ssh-host", aliases: ["sh"], description: SshSession.SSH_OPTION_HOST.description, type: SshSession.SSH_OPTION_HOST.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_PORT: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_PORT: ICommandOptionDefinition = { name: "ssh-port", aliases: ["sp"], description: SshSession.SSH_OPTION_PORT.description, type: SshSession.SSH_OPTION_PORT.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_USER: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_USER: ICommandOptionDefinition = { name: "ssh-user", aliases: ["su"], description: SshSession.SSH_OPTION_USER.description, type: SshSession.SSH_OPTION_USER.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_PASSWORD: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_PASSWORD: ICommandOptionDefinition = { name: "ssh-password", aliases: ["spw"], description: SshSession.SSH_OPTION_PASSWORD.description, type: SshSession.SSH_OPTION_PASSWORD.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_PRIVATEKEY: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_PRIVATEKEY: ICommandOptionDefinition = { name: "ssh-private-key", aliases: ["spk"], description: SshSession.SSH_OPTION_PRIVATEKEY.description, type: SshSession.SSH_OPTION_PRIVATEKEY.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_KEYPASSPHRASE: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_KEYPASSPHRASE: ICommandOptionDefinition = { name: "ssh-key-passphrase", aliases: ["skp"], description: SshSession.SSH_OPTION_KEYPASSPHRASE.description, type: SshSession.SSH_OPTION_KEYPASSPHRASE.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_SSH_OPTION_HANDSHAKETIMEOUT: ICommandOptionDefinition = { + public static CICS_DEPLOY_SSH_OPTION_HANDSHAKETIMEOUT: ICommandOptionDefinition = { name: "ssh-handshake-timeout", aliases: ["sht"], description: SshSession.SSH_OPTION_HANDSHAKETIMEOUT.description, type: SshSession.SSH_OPTION_HANDSHAKETIMEOUT.type, required: false, group: SshSession.SSH_CONNECTION_OPTION_GROUP - }; + }; - /** + /** * Options related to connecting to SSH */ - public static CICS_DEPLOY_SSH_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ - SshOptions.CICS_DEPLOY_SSH_OPTION_HOST, - SshOptions.CICS_DEPLOY_SSH_OPTION_PORT, - SshOptions.CICS_DEPLOY_SSH_OPTION_USER, - SshOptions.CICS_DEPLOY_SSH_OPTION_PASSWORD, - SshOptions.CICS_DEPLOY_SSH_OPTION_PRIVATEKEY, - SshOptions.CICS_DEPLOY_SSH_OPTION_KEYPASSPHRASE, - SshOptions.CICS_DEPLOY_SSH_OPTION_HANDSHAKETIMEOUT - ]; + public static CICS_DEPLOY_SSH_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ + SshOptions.CICS_DEPLOY_SSH_OPTION_HOST, + SshOptions.CICS_DEPLOY_SSH_OPTION_PORT, + SshOptions.CICS_DEPLOY_SSH_OPTION_USER, + SshOptions.CICS_DEPLOY_SSH_OPTION_PASSWORD, + SshOptions.CICS_DEPLOY_SSH_OPTION_PRIVATEKEY, + SshOptions.CICS_DEPLOY_SSH_OPTION_KEYPASSPHRASE, + SshOptions.CICS_DEPLOY_SSH_OPTION_HANDSHAKETIMEOUT + ]; } diff --git a/src/cli/shared/BundleParent.handler.ts b/src/cli/shared/BundleParent.handler.ts index 100541b6..b418c2bd 100644 --- a/src/cli/shared/BundleParent.handler.ts +++ b/src/cli/shared/BundleParent.handler.ts @@ -32,55 +32,55 @@ export abstract class BundleParentHandler implements ICommandHandler { // Initialise Imperative if it is not already initialised try { - // But not if silent mode is requested (i.e. unit tests) - if (params.arguments.silent === undefined) { - await Imperative.init(); - } + // But not if silent mode is requested (i.e. unit tests) + if (params.arguments.silent === undefined) { + await Imperative.init(); + } } catch (err) { - // Imperative may refuse to initialise in unit tests... never mind + // Imperative may refuse to initialise in unit tests... never mind } // log the arguments on entry to the Handler const logger = Logger.getAppLogger(); if (params.arguments.silent === undefined) { - // Strip passwords from the data before logging it - let inputParms = JSON.stringify(params.arguments); - inputParms = this.replacePassword(inputParms, params.arguments.zpw); - inputParms = this.replacePassword(inputParms, params.arguments.spw); - inputParms = this.replacePassword(inputParms, params.arguments.cpw); + // Strip passwords from the data before logging it + let inputParms = JSON.stringify(params.arguments); + inputParms = this.replacePassword(inputParms, params.arguments.zpw); + inputParms = this.replacePassword(inputParms, params.arguments.spw); + inputParms = this.replacePassword(inputParms, params.arguments.cpw); - logger.debug("Arguments received by cics-deploy: " + inputParms); + logger.debug("Arguments received by cics-deploy: " + inputParms); } try { - let msg; - - // Perform an action. Each sub-class will implement its own action and - // either throw an Exception or return a success message. - msg = await this.performAction(params); - - // Add a newline char if its needed - if (msg.slice(-1) !== "\n") { - msg += "\n"; - } - - // Issue the success message - params.response.console.log(Buffer.from(msg)); - if (params.arguments.silent === undefined) { - logger.debug(msg); - } + let msg; + + // Perform an action. Each sub-class will implement its own action and + // either throw an Exception or return a success message. + msg = await this.performAction(params); + + // Add a newline char if its needed + if (msg.slice(-1) !== "\n") { + msg += "\n"; + } + + // Issue the success message + params.response.console.log(Buffer.from(msg)); + if (params.arguments.silent === undefined) { + logger.debug(msg); + } } catch (except) { - // Construct an error message for the exception - const msg = "A failure occurred during CICS bundle " + this.actionName + ".\n Reason = " + except.message; + // Construct an error message for the exception + const msg = "A failure occurred during CICS bundle " + this.actionName + ".\n Reason = " + except.message; - // Log the error message to the Imperative log - if (params.arguments.silent === undefined) { - logger.error(msg); - } + // Log the error message to the Imperative log + if (params.arguments.silent === undefined) { + logger.error(msg); + } - throw new ImperativeError({msg, causeErrors: except}); + throw new ImperativeError({msg, causeErrors: except}); } } @@ -93,12 +93,12 @@ export abstract class BundleParentHandler implements ICommandHandler { * @throws ImperativeError * @memberof BundleParentHandler */ - public abstract async performAction(params: IHandlerParameters): Promise; + public abstract performAction(params: IHandlerParameters): Promise; private replacePassword(source: string, pwd: string): string { - if (pwd !== undefined) { - return source.split(pwd).join("*REDACTED*"); - } - return source; + if (pwd !== undefined) { + return source.split(pwd).join("*REDACTED*"); + } + return source; } } diff --git a/src/cli/shared/ZosmfOptions.ts b/src/cli/shared/ZosmfOptions.ts index abd5e961..b782ea34 100644 --- a/src/cli/shared/ZosmfOptions.ts +++ b/src/cli/shared/ZosmfOptions.ts @@ -17,69 +17,69 @@ import { ZosmfSession } from "@zowe/cli"; */ export class ZosmfOptions { - public static CICS_DEPLOY_ZOSMF_OPTION_HOST: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_HOST: ICommandOptionDefinition = { name: "zosmf-host", aliases: ["zh"], description: ZosmfSession.ZOSMF_OPTION_HOST.description, type: ZosmfSession.ZOSMF_OPTION_HOST.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_ZOSMF_OPTION_PORT: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_PORT: ICommandOptionDefinition = { name: "zosmf-port", aliases: ["zp"], description: ZosmfSession.ZOSMF_OPTION_PORT.description, type: ZosmfSession.ZOSMF_OPTION_PORT.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_ZOSMF_OPTION_USER: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_USER: ICommandOptionDefinition = { name: "zosmf-user", aliases: ["zu"], description: ZosmfSession.ZOSMF_OPTION_USER.description, type: ZosmfSession.ZOSMF_OPTION_USER.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_ZOSMF_OPTION_PASSWORD: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_PASSWORD: ICommandOptionDefinition = { name: "zosmf-password", aliases: ["zpw"], description: ZosmfSession.ZOSMF_OPTION_PASSWORD.description, type: ZosmfSession.ZOSMF_OPTION_PASSWORD.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_ZOSMF_OPTION_REJECT_UNAUTHORIZED: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_REJECT_UNAUTHORIZED: ICommandOptionDefinition = { name: "zosmf-reject-unauthorized", aliases: ["zru"], description: ZosmfSession.ZOSMF_OPTION_REJECT_UNAUTHORIZED.description, type: ZosmfSession.ZOSMF_OPTION_REJECT_UNAUTHORIZED.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - public static CICS_DEPLOY_ZOSMF_OPTION_BASE_PATH: ICommandOptionDefinition = { + public static CICS_DEPLOY_ZOSMF_OPTION_BASE_PATH: ICommandOptionDefinition = { name: "zosmf-base-path", aliases: ["zbp"], description: ZosmfSession.ZOSMF_OPTION_BASE_PATH.description, type: ZosmfSession.ZOSMF_OPTION_BASE_PATH.type, required: false, group: ZosmfSession.ZOSMF_CONNECTION_OPTION_GROUP - }; + }; - /** + /** * Options related to connecting to z/OSMF */ - public static CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_HOST, - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_PORT, - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_USER, - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_PASSWORD, - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_REJECT_UNAUTHORIZED, - ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_BASE_PATH - ]; + public static CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS: ICommandOptionDefinition[] = [ + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_HOST, + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_PORT, + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_USER, + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_PASSWORD, + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_REJECT_UNAUTHORIZED, + ZosmfOptions.CICS_DEPLOY_ZOSMF_OPTION_BASE_PATH + ]; } diff --git a/src/cli/undeploy/bundle/UndeployBundle.definition.ts b/src/cli/undeploy/bundle/UndeployBundle.definition.ts index d55ecb30..a557498b 100644 --- a/src/cli/undeploy/bundle/UndeployBundle.definition.ts +++ b/src/cli/undeploy/bundle/UndeployBundle.definition.ts @@ -37,9 +37,9 @@ export const UndeployBundleDefinition: ICommandDefinition = { type: "command", handler: __dirname + "/UndeployBundle.handler", options: [ NameOption, CicsplexOption, ScopeOption, CsdgroupOption , ResgroupOption, - CicshlqOption, CpsmhlqOption, JobcardOption, TimeoutOption, TargetStateOption, - VerboseOption] - .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS), + CicshlqOption, CpsmhlqOption, JobcardOption, TimeoutOption, TargetStateOption, + VerboseOption] + .concat(ZosmfOptions.CICS_DEPLOY_ZOSMF_CONNECTION_OPTIONS), profile: { optional: ["cics-deploy", "zosmf"] }, examples: [ { diff --git a/src/cli/undeploy/bundle/UndeployBundle.handler.ts b/src/cli/undeploy/bundle/UndeployBundle.handler.ts index f1f76c2b..958733bb 100644 --- a/src/cli/undeploy/bundle/UndeployBundle.handler.ts +++ b/src/cli/undeploy/bundle/UndeployBundle.handler.ts @@ -32,8 +32,8 @@ export default class UndeployBundleHandler extends BundleParentHandler implement * @memberof UndeployBundleHandler */ public async performAction(params: IHandlerParameters): Promise { - const bdep = new BundleDeployer(params); - const msg = await bdep.undeployBundle(); - return msg; + const bdep = new BundleDeployer(params); + const msg = await bdep.undeployBundle(); + return msg; } } diff --git a/src/cli/undeploy/bundle/options/TargetState.option.ts b/src/cli/undeploy/bundle/options/TargetState.option.ts index 631b7d79..bc78bf17 100644 --- a/src/cli/undeploy/bundle/options/TargetState.option.ts +++ b/src/cli/undeploy/bundle/options/TargetState.option.ts @@ -22,8 +22,8 @@ export const TargetStateOption: ICommandOptionDefinition = { required: false, defaultValue: "DISCARDED", allowableValues: { - values: ["UNAVAILABLE", "DISABLED", "DISCARDED"], - caseSensitive: false + values: ["UNAVAILABLE", "DISABLED", "DISCARDED"], + caseSensitive: false }, group: "cics-deploy Options", description: "Specifies the target state for the undeployed bundle." diff --git a/src/healthCheck.handler.ts b/src/healthCheck.handler.ts index fbe5888f..e7d1fbcc 100644 --- a/src/healthCheck.handler.ts +++ b/src/healthCheck.handler.ts @@ -12,11 +12,11 @@ import {ICommandHandler, IHandlerParameters, Logger} from "@zowe/imperative"; export default class HealthCheckHandler implements ICommandHandler { - public async process(params: IHandlerParameters): Promise { - Logger.getImperativeLogger().debug("Invoked health check handler"); - params.response.console.log("You would report problems identified by healthCheck.\n" + + public async process(params: IHandlerParameters): Promise { + Logger.getImperativeLogger().debug("Invoked health check handler"); + params.response.console.log("You would report problems identified by healthCheck.\n" + "This handler is not currently called by Imperative, but\n" + "its existence prevents a warning during plugin validation." - ); - } + ); + } } diff --git a/src/imperative.ts b/src/imperative.ts index 03bf380d..eb733e67 100644 --- a/src/imperative.ts +++ b/src/imperative.ts @@ -25,131 +25,132 @@ const config: IImperativeConfig = { productDisplayName: "Zowe cics-deploy plug-in", name: "cics-deploy", profiles: [ - { - type: "cics-deploy", - schema: { - type: "object", - title: "The cics-deploy-profile schema", - description: "Specifies the target environment for the cics-deploy deploy and undeploy actions.", - properties: { - "cicsplex": { - optionDefinition: { - description: "Specifies the CICSplex (up to 8 characters) to target.", - type: "string", - name: "cicsplex", - aliases: ["cp"], - stringLengthRange: [1, MAX_LENGTH], - required: true - }, - type: "string" - }, - "scope": { - optionDefinition: { - description: "Specifies the name of the CICS System, or CICS System Group " + + { + type: "cics-deploy", + schema: { + type: "object", + title: "The cics-deploy-profile schema", + description: "Specifies the target environment for the cics-deploy deploy and undeploy actions.", + properties: { + "cicsplex": { + optionDefinition: { + description: "Specifies the CICSplex (up to 8 characters) to target.", + type: "string", + name: "cicsplex", + aliases: ["cp"], + stringLengthRange: [1, MAX_LENGTH], + required: true + }, + type: "string" + }, + "scope": { + optionDefinition: { + description: "Specifies the name of the CICS System, or CICS System Group " + "(up to 8 characters) to target.", - type: "string", - name: "scope", - aliases: ["sc"], - stringLengthRange: [1, MAX_LENGTH], - required: true - }, - type: "string" - }, - "csd-group": { - optionDefinition: { - description: "Specifies the CSD group (up to 8 characters) for the bundle resource. If a bundle is " + + type: "string", + name: "scope", + aliases: ["sc"], + stringLengthRange: [1, MAX_LENGTH], + required: true + }, + type: "string" + }, + "csd-group": { + optionDefinition: { + description: "Specifies the CSD group (up to 8 characters) for the bundle resource. If a bundle is " + "deployed then a definition is added to this group; if a bundle is undeployed then the " + "definition is removed from this group. The CSD group is changed for each CICS system " + "that is specified by the --scope option. The --csd-group and --res-group options are " + "mutually exclusive.", - type: "string", - name: "csd-group", - aliases: ["cg", "csdgroup"], - stringLengthRange: [1, MAX_LENGTH] - }, - type: "string" - }, - "res-group": { - optionDefinition: { - description: "Specifies the BAS resource group (up to 8 characters) for the bundle resource. If a bundle is " + + type: "string", + name: "csd-group", + aliases: ["cg", "csdgroup"], + stringLengthRange: [1, MAX_LENGTH] + }, + type: "string" + }, + "res-group": { + optionDefinition: { + description: "Specifies the BAS resource group (up to 8 characters) for the bundle resource. If a bundle is " + "deployed then a resource is defined in the BAS data repository; if a bundle is undeployed then the " + "definition is removed. The --csd-group and --res-group options are mutually exclusive.", - type: "string", - name: "res-group", - aliases: ["rg", "resgroup"], - stringLengthRange: [1, MAX_LENGTH], - conflictsWith: [ "csd-group" ], - }, - type: "string" - }, - "cics-hlq": { - optionDefinition: { - description: "Specifies the High Level Qualifier (up to 35 characters) at which the CICS " + + type: "string", + name: "res-group", + aliases: ["rg", "resgroup"], + stringLengthRange: [1, MAX_LENGTH], + conflictsWith: [ "csd-group" ], + }, + type: "string" + }, + "cics-hlq": { + optionDefinition: { + description: "Specifies the High Level Qualifier (up to 35 characters) at which the CICS " + "datasets can be found in the target environment.", - type: "string", - name: "cics-hlq", - aliases: ["cq", "cicshlq"], - stringLengthRange: [1, MAX_HLQ_LENGTH], - required: true - }, - type: "string" - }, - "cpsm-hlq": { - optionDefinition: { - description: "Specifies the High Level Qualifier (up to 35 characters) at which the CPSM " + + type: "string", + name: "cics-hlq", + aliases: ["cq", "cicshlq"], + stringLengthRange: [1, MAX_HLQ_LENGTH], + required: true + }, + type: "string" + }, + "cpsm-hlq": { + optionDefinition: { + description: "Specifies the High Level Qualifier (up to 35 characters) at which the CPSM " + "datasets can be found in the target environment.", - type: "string", - name: "cpsm-hlq", - aliases: ["cph", "cpsmhlq"], - stringLengthRange: [1, MAX_HLQ_LENGTH], - required: true - }, - type: "string" - }, - "target-directory": { - optionDefinition: { - description: "Specifies the target zFS location to which CICS bundles should be uploaded (up to 255 characters).", - type: "string", - name: "target-directory", - aliases: ["td", "targetdir", "target-dir"], - stringLengthRange: [1, MAX_TARGETDIR_LENGTH], - required: false - }, - type: "string" + type: "string", + name: "cpsm-hlq", + aliases: ["cph", "cpsmhlq"], + stringLengthRange: [1, MAX_HLQ_LENGTH], + required: true + }, + type: "string" + }, + "target-directory": { + optionDefinition: { + description: "Specifies the target zFS location to which CICS bundles should be uploaded (up to 255 characters).", + type: "string", + name: "target-directory", + aliases: ["td", "targetdir", "target-dir"], + stringLengthRange: [1, MAX_TARGETDIR_LENGTH], + required: false + }, + type: "string" + }, + "job-card": { + optionDefinition: { + description: "Specifies the job card to use with any generated DFHDPLOY JCL.", + type: "string", + name: "job-card", + defaultValue: "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT", + aliases: ["jc", "jobcard"], + required: true + }, + type: "string" + } + }, + required: ["cicsplex", "scope", "cics-hlq", "cpsm-hlq", "job-card"] }, - "job-card": { - optionDefinition: { - description: "Specifies the job card to use with any generated DFHDPLOY JCL.", - type: "string", - name: "job-card", - defaultValue: "//DFHDPLOY JOB DFHDPLOY,CLASS=A,MSGCLASS=X,TIME=NOLIMIT", - aliases: ["jc", "jobcard"], - required: true - }, - type: "string" - } - }, - required: ["cicsplex", "scope", "cics-hlq", "cpsm-hlq", "job-card"] - }, - createProfileExamples: [ - { - options: "example1 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550", - description: "Create a cics-deploy profile called 'example1' to connect to a CPSM managed group of CICS regions " + + createProfileExamples: [ + { + options: "example1 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550", + description: "Create a cics-deploy profile called 'example1' to connect to a CPSM managed group of CICS regions " + "within the TESTGRP1 scope of a cicsplex named PLEX1" - }, - { - options: "example2 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 --res-group BUNDGRP1", - description: "Create a cics-deploy profile called 'example2' to connect to the same CPSM managed group of regions, " + + }, + { + options: "example2 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 --cpsm-hlq CICSTS55.CPSM550 " + + "--res-group BUNDGRP1", + description: "Create a cics-deploy profile called 'example2' to connect to the same CPSM managed group of regions, " + "and identify a BAS resource group BUNDGRP1 in which to store resource definitions" - }, - { - options: "example3 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 " + + }, + { + options: "example3 --cicsplex PLEX1 --scope TESTGRP1 --cics-hlq CICSTS55.CICS720 " + "--cpsm-hlq CICSTS55.CPSM550 --target-directory /var/cicsts/bundles", - description: "Create a cics-deploy profile called 'example3' to connect to the same CPSM managed group of regions, " + + description: "Create a cics-deploy profile called 'example3' to connect to the same CPSM managed group of regions, " + "and identify the default USS directory to which bundles should be uploaded" - } - ] - } + } + ] + } ] }; diff --git a/tsconfig.json b/tsconfig.json index 6694ec38..9dacc39f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,13 +17,12 @@ "newLine": "lf" }, "include": [ - "src/**/*" + "src/**/*.ts", + "__tests__/**/*.ts" ], "exclude": [ "lib", "node_modules", - "**/__mocks__/*", - "**/__tests__/*", - "**/*.test.ts" + "**/__mocks__/*" ] - } \ No newline at end of file + } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index b8366be1..00000000 --- a/tslint.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "extends": "tslint:latest", - "rules": { - "object-literal-sort-keys": false, - "ordered-imports": false, - "one-line": false, - "space-within-parens": false, - "no-var-requires": false, - "trailing-comma": false, - "no-submodule-imports": [ - true - ], - "max-line-length": [ - true, - 150 - ], - "no-magic-numbers": [ - true, - -1, - 0, - 1, - 2 - ], - "no-consecutive-blank-lines": [ - true, - 2 - ], - "prefer-conditional-expression": false, - "no-implicit-dependencies": [true] - }, - "exclude": "node_modules", - "type-check": true - } -