diff --git a/__tests__/__integration__/imperative.secure.integration.test.ts b/__tests__/__integration__/imperative.secure.integration.test.ts index 19393d71ce..091d5a557c 100644 --- a/__tests__/__integration__/imperative.secure.integration.test.ts +++ b/__tests__/__integration__/imperative.secure.integration.test.ts @@ -14,7 +14,6 @@ /* eslint-disable max-len */ describe("Imperative Secure Tests", () => { - require("./../../packages/imperative/__tests__/src/packages/profiles/__integration__/CliProfileManager.credentials.integration.subtest"); require("./../../packages/imperative/__tests__/src/packages/imperative/__integration__/PluginManagementFacility.integration.subtest"); require("./../../packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/init/cli.imperative-test-cli.config.init.integration.subtest"); require("./../../packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/auto-init/imperative.test.cli.config.auto-init.fruit.integration.subtest"); diff --git a/__tests__/__packages__/cli-test-utils/src/TestUtils.ts b/__tests__/__packages__/cli-test-utils/src/TestUtils.ts index 6ad1ce58b6..a61c50b49b 100644 --- a/__tests__/__packages__/cli-test-utils/src/TestUtils.ts +++ b/__tests__/__packages__/cli-test-utils/src/TestUtils.ts @@ -62,17 +62,6 @@ export function runCliScript(scriptPath: string, testEnvironment: ITestEnvironme } } -/** - * Strip v1 profile deprecation messages from stderr output. - */ -export function stripProfileDeprecationMessages(stderr: Buffer | string): string { - return stderr.toString() - .replace(/Warning: The command 'profiles [a-z]+' is deprecated\./g, "") - .replace(/Recommended replacement: The 'config [a-z]+' command/g, "") - .replace(/Recommended replacement: Edit your Zowe V2 configuration\s+zowe\.config\.json/g, "") - .trim(); -} - /** * Type for handler data used to build mock IHandlerParameters object. * The type inherits from IHandlerParameters but is different: diff --git a/__tests__/__packages__/cli-test-utils/src/environment/TempTestProfiles.ts b/__tests__/__packages__/cli-test-utils/src/environment/TempTestProfiles.ts index 74cb912ff4..e50a645942 100644 --- a/__tests__/__packages__/cli-test-utils/src/environment/TempTestProfiles.ts +++ b/__tests__/__packages__/cli-test-utils/src/environment/TempTestProfiles.ts @@ -16,10 +16,9 @@ import * as fs from "fs"; import { v4 as uuidv4 } from "uuid"; -import { Config, ImperativeError, IO } from "@zowe/imperative"; +import { Config } from "@zowe/imperative"; import { ITestEnvironment } from "./doc/response/ITestEnvironment"; -import { runCliScript, stripProfileDeprecationMessages } from "../TestUtils"; /** * Utilities for creating and cleaning up temporary profiles for tests @@ -53,12 +52,6 @@ export class TempTestProfiles { `installed or linked globally so that '${TempTestProfiles.BINARY_NAME}' can be issued to create profiles and ` + `issue other commands.`; - /** - * Override for the ZOWE_CLI_TEST_OLD_PROFILES environment variable. If - * set to true, old-school profiles will be created instead of team config. - */ - public static forceOldProfiles: boolean = false; - /** * Create profiles for tests from data in the properties yaml file * @param {ITestEnvironment} testEnvironment - with working directory and test properties loaded @@ -73,11 +66,7 @@ export class TempTestProfiles { const profileNames: { [key: string]: string[] } = {}; this.log(testEnvironment, "Creating the following profileTypes: " + profileTypes); for (const profileType of profileTypes) { - if (this.usingTeamConfig) { - profileNames[profileType] = [await this.createV2Profile(testEnvironment, profileType)]; - } else { - profileNames[profileType] = [await this.createV1Profile(testEnvironment, profileType)]; - } + profileNames[profileType] = [await this.createV2Profile(testEnvironment, profileType)]; } return profileNames; } @@ -94,11 +83,7 @@ export class TempTestProfiles { this.log(testEnvironment, "Deleting the following profiles:\n" + JSON.stringify(profiles)); for (const profileType of Object.keys(profiles)) { for (const profileName of profiles[profileType]) { - if (this.usingTeamConfig) { - await this.deleteV2Profile(testEnvironment, profileType, profileName); - } else { - await this.deleteV1Profile(testEnvironment, profileType, profileName); - } + await this.deleteV2Profile(testEnvironment, profileType, profileName); } } } @@ -111,44 +96,6 @@ export class TempTestProfiles { */ private static readonly MAX_UUID_LENGTH = 20; - /** - * Whether new team config profiles should be used instead of old school - * profiles. - */ - private static get usingTeamConfig(): boolean { - if (this.forceOldProfiles) return false; - const envOldProfiles = process.env.ZOWE_CLI_TEST_OLD_PROFILES; - return envOldProfiles !== "1" && envOldProfiles?.toLowerCase() !== "true"; - } - - /** - * Helper to create a temporary old school profile from test properties - * @param {ITestEnvironment} testEnvironment - the test environment with env and working directory to use for output - * @returns {Promise} promise that resolves to the name of the created profile on success - * @throws errors if the profile creation fails - */ - private static async createV1Profile(testEnvironment: ITestEnvironment, profileType: string): Promise { - const profileName: string = uuidv4().substring(0, TempTestProfiles.MAX_UUID_LENGTH) + "_tmp_" + profileType; - let createProfileScript = this.SHEBANG + - `${this.BINARY_NAME} profiles create ${profileType} ${profileName}`; - for (const [k, v] of Object.entries(testEnvironment.systemTestProperties[profileType])) { - createProfileScript += ` ${(k.length > 1) ? "--" : "-"}${k} ${v}`; - } - const scriptPath = testEnvironment.workingDir + "_create_profile_" + profileName; - await IO.writeFileAsync(scriptPath, createProfileScript); - const output = runCliScript(scriptPath, testEnvironment, []); - if (output.status !== 0 || stripProfileDeprecationMessages(output.stderr).length > 0) { - throw new ImperativeError({ - msg: `Creation of ${profileType} profile '${profileName}' failed! You should delete the script: ` + - `'${scriptPath}' after reviewing it to check for possible errors. Stderr of the profile create ` + - `command:\n` + output.stderr.toString() + TempTestProfiles.GLOBAL_INSTALL_NOTE - }); - } - IO.deleteFile(scriptPath); - this.log(testEnvironment, `Created ${profileType} V1 profile '${profileName}'. Stdout from creation:\n${output.stdout.toString()}`); - return profileName; - } - /** * Helper to create a temporary team config profile from test properties * @internal @@ -176,31 +123,6 @@ export class TempTestProfiles { return profileName; } - /** - * Helper to delete a temporary old school profile - * @param {ITestEnvironment} testEnvironment - the test environment with env and working directory to use for output - * @param {string} profileType - the type of profile e.g. zosmf to - * @param {string} profileName - the name of the profile to delete - * @returns {Promise} promise that resolves to the name of the created profile on success - * @throws errors if the profile delete fails - */ - private static async deleteV1Profile(testEnvironment: ITestEnvironment, profileType: string, profileName: string): Promise { - const deleteProfileScript = this.SHEBANG + `${this.BINARY_NAME} profiles delete ${profileType} ${profileName} --force`; - const scriptPath = testEnvironment.workingDir + "_delete_profile_" + profileName; - await IO.writeFileAsync(scriptPath, deleteProfileScript); - const output = runCliScript(scriptPath, testEnvironment, []); - if (output.status !== 0 || stripProfileDeprecationMessages(output.stderr).length > 0) { - throw new ImperativeError({ - msg: "Deletion of " + profileType + " profile '" + profileName + "' failed! You should delete the script: '" + scriptPath + "' " + - "after reviewing it to check for possible errors. Stderr of the profile create command:\n" + output.stderr.toString() - + TempTestProfiles.GLOBAL_INSTALL_NOTE - }); - } - this.log(testEnvironment, `Deleted ${profileType} V1 profile '${profileName}'. Stdout from deletion:\n${output.stdout.toString()}`); - IO.deleteFile(scriptPath); - return profileName; - } - /** * Helper to delete a temporary team config profile * @internal diff --git a/__tests__/__packages__/cli-test-utils/src/environment/TestEnvironment.ts b/__tests__/__packages__/cli-test-utils/src/environment/TestEnvironment.ts index fc7503663a..2ebefad416 100644 --- a/__tests__/__packages__/cli-test-utils/src/environment/TestEnvironment.ts +++ b/__tests__/__packages__/cli-test-utils/src/environment/TestEnvironment.ts @@ -75,8 +75,7 @@ export class TestEnvironment { } // the result of the test environment setup so far is used to create profiles - TempTestProfiles.forceOldProfiles = params.createOldProfiles ?? false; - if (TempTestProfiles.forceOldProfiles || (params.tempProfileTypes?.length ?? 0 > 0)) { + if (params.tempProfileTypes?.length ?? 0 > 0) { result.tempProfiles = await TempTestProfiles.createProfiles(result, params.tempProfileTypes); } diff --git a/__tests__/__packages__/cli-test-utils/src/environment/doc/parms/ISetupEnvironmentParms.ts b/__tests__/__packages__/cli-test-utils/src/environment/doc/parms/ISetupEnvironmentParms.ts index be5aa2a5eb..08e865b35a 100644 --- a/__tests__/__packages__/cli-test-utils/src/environment/doc/parms/ISetupEnvironmentParms.ts +++ b/__tests__/__packages__/cli-test-utils/src/environment/doc/parms/ISetupEnvironmentParms.ts @@ -53,10 +53,4 @@ export interface ISetupEnvironmentParms { * you are trying to execute plugin commands installed into Zowe CLI. */ installPlugin?: boolean; - - /** - * Should old-school profiles be created instead of team config? - * Default: false - */ - createOldProfiles?: boolean; } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 62748830f6..dc6de93ff3 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -17398,7 +17398,7 @@ "which": "^4.0.0" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "optionalDependencies": { "@zowe/secrets-for-zowe-sdk": "8.0.0-next.202402271901" @@ -17459,7 +17459,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next" @@ -17531,7 +17531,7 @@ "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" } }, "packages/imperative/node_modules/cliui": { @@ -17700,7 +17700,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17733,7 +17733,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17750,7 +17750,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17770,6 +17770,9 @@ "@zowe/imperative": "8.0.0-next.202402271901", "@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202402271901" }, + "engines": { + "node": ">=18.12.0" + }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", "@zowe/imperative": "^8.0.0-next" @@ -17808,7 +17811,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17825,7 +17828,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17842,7 +17845,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17862,7 +17865,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/core-for-zowe-sdk": "^8.0.0-next", @@ -17882,7 +17885,7 @@ "@zowe/imperative": "8.0.0-next.202402271901" }, "engines": { - "node": ">=16.7.0" + "node": ">=18.12.0" }, "peerDependencies": { "@zowe/imperative": "^8.0.0-next" diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index d46c105a59..aa4b2fa99f 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to the Zowe CLI package will be documented in this file. ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- BugFix: Eliminated a Node Version Manager (NVM) GUI popup dialog which NVM now displays during the `zowe config report-env` command by removing the NVM version number from our report. +- Enhancement: Replaced the term "Team configuration" with "Zowe client configuration" in the `zowe config report-env` command. ## `8.0.0-next.202402261705` @@ -41,7 +43,7 @@ LTS Breaking: Removed the following previously deprecated items: [#1981](https:/ - SSH_OPTION_HOST_PROFILE use SSH_OPTION_HOST - Removed zosmfProfile from `ZosFilesBase.handler.ts` - Removed statCmdFlag as an export from Shell.ts - + ## `8.0.0-next.202401262128` diff --git a/packages/cli/__tests__/zosfiles/__unit__/copy/dsclp/TargetProfile.handler.unit.test.ts b/packages/cli/__tests__/zosfiles/__unit__/copy/dsclp/TargetProfile.handler.unit.test.ts index 556f605d23..4a756e9d0d 100644 --- a/packages/cli/__tests__/zosfiles/__unit__/copy/dsclp/TargetProfile.handler.unit.test.ts +++ b/packages/cli/__tests__/zosfiles/__unit__/copy/dsclp/TargetProfile.handler.unit.test.ts @@ -79,47 +79,6 @@ describe("TargetProfileHandler", () => { }); }); - it("should merge properties from v1 profiles and command arguments", async () => { - const commandParameters = { - ...DEFAULT_PARAMETERS, - arguments: { - ...DEFAULT_PARAMETERS.arguments, - host: "example1.com", - user: "user1", - password: "password1", - targetUser: "user2", - targetPassword: "password3", - targetZosmfProfile: "target_zosmf" - } - }; - - commandParameters.response.data.setObj = jest.fn(); - const getProfileMock = jest.fn().mockReturnValue({ - password: "password2", - port: 123 - }); - commandParameters.profiles.get = getProfileMock; - jest.spyOn(ImperativeConfig, "instance", "get").mockReturnValue({ - config: { exists: false } - } as any); - - const handler = new TargetProfileHandler(); - await handler.process(commandParameters); - - expect(getProfileMock).toHaveBeenCalledTimes(1); - expect(commandParameters.response.data.setObj).toHaveBeenCalledWith({ - apiResponse: { - sessCfg: expect.objectContaining({ - hostname: "example1.com", - port: 123, - user: "user2", - password: "password3" - }) - }, - success: true - }); - }); - it("should handle error loading target z/OSMF profile", async () => { const commandParameters = { ...DEFAULT_PARAMETERS, diff --git a/packages/cli/__tests__/zosjobs/__unit__/submit/Submit.shared.handler.unit.test.ts b/packages/cli/__tests__/zosjobs/__unit__/submit/Submit.shared.handler.unit.test.ts index dc5db960fc..79ff419564 100644 --- a/packages/cli/__tests__/zosjobs/__unit__/submit/Submit.shared.handler.unit.test.ts +++ b/packages/cli/__tests__/zosjobs/__unit__/submit/Submit.shared.handler.unit.test.ts @@ -71,7 +71,7 @@ describe("submit shared handler", () => { expect(error).toBeDefined(); expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); + expect(error.message).toContain("Unable to determine the JCL source. Please contact support"); }); it("should not transform an error thrown by the submit JCL API", async () => { diff --git a/packages/cli/__tests__/zosjobs/__unit__/submit/__snapshots__/Submit.shared.handler.unit.test.ts.snap b/packages/cli/__tests__/zosjobs/__unit__/submit/__snapshots__/Submit.shared.handler.unit.test.ts.snap index 4d0cd3442d..9303956249 100644 --- a/packages/cli/__tests__/zosjobs/__unit__/submit/__snapshots__/Submit.shared.handler.unit.test.ts.snap +++ b/packages/cli/__tests__/zosjobs/__unit__/submit/__snapshots__/Submit.shared.handler.unit.test.ts.snap @@ -1,7 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`submit shared handler error handling should detect if the JCL source type (data set, etc.) could not be determined 1`] = `"Internal submit error: Unable to determine the JCL source. Please contact support."`; - exports[`submit shared handler process method should submit JCL contained within a data-set if requested 1`] = ` Object { "fields": Array [ diff --git a/packages/cli/src/zosfiles/copy/dsclp/TargetProfile.handler.ts b/packages/cli/src/zosfiles/copy/dsclp/TargetProfile.handler.ts index 14f16f86fc..16d046e0f0 100644 --- a/packages/cli/src/zosfiles/copy/dsclp/TargetProfile.handler.ts +++ b/packages/cli/src/zosfiles/copy/dsclp/TargetProfile.handler.ts @@ -28,11 +28,7 @@ export default class TargetProfileHandler extends ZosFilesBaseHandler { try { if (targetProfileName != null) { - if (ImperativeConfig.instance.config?.exists) { - targetCmdArgs = ImperativeConfig.instance.config.api.profiles.get(targetProfileName); - } else { - targetCmdArgs = params.profiles.get("zosmf", false, targetProfileName); - } + targetCmdArgs = ImperativeConfig.instance.config.api.profiles.get(targetProfileName); } const targetPrefix = "target"; diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 6d6538a89d..58c34d51ef 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to the Zowe core SDK package will be documented in this file ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- LTS Breaking: Removed the file ProfileUtils.ts which contains the following obsolete V1 profile functions: + - getDefaultProfile + - getZoweDir - moved to ProfileInfo.getZoweDir ## `8.0.0-next.202402261705` diff --git a/packages/core/__tests__/utils/__integration__/ProfileUtils.integration.test.ts b/packages/core/__tests__/utils/__integration__/ProfileUtils.integration.test.ts deleted file mode 100644 index 533d6e525c..0000000000 --- a/packages/core/__tests__/utils/__integration__/ProfileUtils.integration.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - - -import * as imperative from "@zowe/imperative"; -import * as profileUtils from "../../../src/utils/ProfileUtils"; -import { ITestEnvironment, runCliScript } from "@zowe/cli-test-utils"; -import { TestEnvironment } from "../../../../../__tests__/__src__/environment/TestEnvironment"; -import { ITestPropertiesSchema } from "../../../../../__tests__/__src__/properties/ITestPropertiesSchema"; - -const fs = require("fs"); - -const fakeServiceProfile: imperative.IProfile = { - name: "fakeServiceProfile", - type: "zosmf", - host: "fakeHostService" -}; - -const fakeBaseProfile: imperative.IProfile = { - name: "fakeBaseProfile", - type: "base", - host: "fakeHostBase" -}; - -const fakeProfileMissingInformation: imperative.IProfile = { - name: "fakeServiceProfile", - type: "zosmf", - host: undefined -}; - -// Test Environment populated in the beforeAll(); -let TEST_ENVIRONMENT: ITestEnvironment; - -describe("ProfileUtils", () => { - describe("getDefaultProfile", () => { - beforeAll(async () => { - TEST_ENVIRONMENT = await TestEnvironment.setUp({ - testName: "core_utils_get_default_profile", - skipProperties: true - }); - process.env.ZOWE_CLI_HOME = TEST_ENVIRONMENT.workingDir; - - // copy existing profiles into test directory - const response = runCliScript(__dirname + "/__scripts__/copy_profiles.sh", TEST_ENVIRONMENT); - expect(response.stderr.toString()).toBe(""); - expect(response.status).toBe(0); - }); - - beforeEach(() => { - jest.resetAllMocks(); - - // Pretend that we have no team config - Object.defineProperty(imperative.ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - }); - - afterAll(async () => { - await TestEnvironment.cleanUp(TEST_ENVIRONMENT); - }); - - - it("Should return a service profile", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load") - .mockResolvedValueOnce({ profile: fakeServiceProfile } as any); - let error; - let profile: imperative.IProfile; - try { - profile = await profileUtils.getDefaultProfile("zosmf", false); - } catch (err) { - error = err; - } - expect(error).not.toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(1); - expect(profile).toEqual(fakeServiceProfile); - }); - it("Should return a service profile even though base is missing", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load") - .mockResolvedValueOnce({ profile: fakeServiceProfile } as any) - .mockResolvedValueOnce({ profile: undefined } as any); - let error; - let profile: imperative.IProfile; - try { - profile = await profileUtils.getDefaultProfile("zosmf", true); - } catch (err) { - error = err; - } - expect(error).not.toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(2); - expect(profile).toEqual(fakeServiceProfile); - }); - it("Should return a base profile", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load") - .mockResolvedValueOnce({ profile: undefined } as any) - .mockResolvedValueOnce({ profile: fakeBaseProfile } as any); - let error; - let profile: imperative.IProfile; - try { - profile = await profileUtils.getDefaultProfile("zosmf", true); - } catch (err) { - error = err; - } - expect(error).not.toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(2); - expect(profile).toEqual(fakeBaseProfile); - }); - it("Should return a service profile even though base was specified", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load") - .mockResolvedValueOnce({ profile: fakeServiceProfile } as any) - .mockResolvedValueOnce({ profile: fakeBaseProfile } as any); - let error; - let profile: imperative.IProfile; - try { - profile = await profileUtils.getDefaultProfile("zosmf", true); - } catch (err) { - error = err; - } - expect(error).not.toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(2); - expect(profile).toEqual(fakeServiceProfile); - }); - it("Should properly combine profiles", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load") - .mockResolvedValueOnce({ profile: fakeProfileMissingInformation } as any) - .mockResolvedValueOnce({ profile: fakeBaseProfile } as any); - let error; - let profile: imperative.IProfile; - try { - profile = await profileUtils.getDefaultProfile("zosmf", true); - } catch (err) { - error = err; - } - expect(error).not.toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(2); - expect(profile).toEqual({name: "fakeServiceProfile", type: "zosmf", host: "fakeHostBase"}); - }); - it("Should throw an error if it cannot get the service profile", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load").mockResolvedValueOnce({ profile: undefined } as any); - let error; - try { - await profileUtils.getDefaultProfile("zosmf", false); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(1); - expect(error.message).toContain("zosmf"); - }); - it("Should throw an error if it cannot get both profiles", async() => { - const profileManagerSpy = jest.spyOn(imperative.CliProfileManager.prototype, "load").mockResolvedValue({ profile: undefined } as any); - let error; - try { - await profileUtils.getDefaultProfile("zosmf", true); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(profileManagerSpy).toHaveBeenCalledTimes(2); - expect(error.message).toContain("zosmf"); - expect(error.message).toContain("base"); - }); - }); -}); \ No newline at end of file diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/base_meta.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/base_meta.yaml deleted file mode 100644 index 4b73a7496f..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/base_meta.yaml +++ /dev/null @@ -1,230 +0,0 @@ -defaultProfile: fakeBaseProfile -configuration: - type: base - schema: - type: object - title: 'Base Profile' - description: 'Base profile that stores values shared by multiple service profiles' - properties: - host: - type: string - optionDefinition: - name: host - aliases: - - H - description: 'Host name of service on the mainframe.' - type: string - group: 'Base Connection Options' - includeInTemplate: true - port: - type: number - optionDefinition: - name: port - aliases: - - P - description: 'Port number of service on the mainframe.' - type: number - group: 'Base Connection Options' - user: - type: string - secure: true - optionDefinition: - name: user - aliases: - - u - description: 'User name to authenticate to service on the mainframe.' - type: string - group: 'Base Connection Options' - includeInTemplate: true - password: - type: string - secure: true - optionDefinition: - name: password - aliases: - - pass - - pw - description: 'Password to authenticate to service on the mainframe.' - type: string - group: 'Base Connection Options' - includeInTemplate: true - rejectUnauthorized: - type: boolean - optionDefinition: - name: reject-unauthorized - aliases: - - ru - description: 'Reject self-signed certificates.' - type: boolean - defaultValue: true - group: 'Base Connection Options' - includeInTemplate: true - tokenType: - type: string - optionDefinition: - name: token-type - aliases: - - tt - description: 'The type of token to get and use for the API. Omit this option to use the default token type, which is provided by ''zowe auth login''.' - type: string - group: 'Base Connection Options' - tokenValue: - type: string - secure: true - optionDefinition: - name: token-value - aliases: - - tv - description: 'The value of the token to pass to the API.' - type: string - group: 'Base Connection Options' - certFile: - type: string - optionDefinition: - name: cert-file - description: 'The file path to a certificate file to use for authentication' - type: existingLocalFile - group: 'Base Connection Options' - aliases: [] - certKeyFile: - type: string - optionDefinition: - name: cert-key-file - description: 'The file path to a certificate key file to use for authentication' - type: existingLocalFile - group: 'Base Connection Options' - aliases: [] - required: [] - createProfileExamples: - - - options: 'base1 --host example.com --port 443 --user admin --password 123456' - description: 'Create a profile called ''base1'' to connect to host example.com and port 443' - - - options: 'base2 --host example.com --user admin --password 123456 --reject-unauthorized false' - description: 'Create a profile called ''base2'' to connect to host example.com (default port - 443) and allow self-signed certificates' - - - options: 'base3 --host example.com --port 1443' - description: 'Create a profile called ''base3'' to connect to host example.com and port 1443, not specifying a username or password so they are not stored on disk; these will need to be specified on every command' - - - options: 'base4 --reject-unauthorized false' - description: 'Create a zosmf profile called ''base4'' to connect to default port 443 and allow self-signed certificates, not specifying a username, password, or host so they are not stored on disk; these will need to be specified on every command' - updateProfileExamples: - - - options: 'base1 --user newuser --password newp4ss' - description: 'Update a base profile named ''base1'' with a new username and password' - authConfig: - - - serviceName: apiml - handler: /home/stduser/repos/zowe-cli/packages/cli/lib/auth/ApimlAuthHandler - login: - summary: 'Log in to API ML authentication service' - description: "Log in to Zowe API Mediation Layer authentication service and obtain or update a token.\n\nThe token provides authentication to services that support the API ML SSO (Single Sign-On) capability. When you log in, the token is stored in your default base profile until it expires. Base profiles store connection information shared by multiple services (e.g., z/OSMF), and are used if you do not supply connection information in a service profile. To take advantage of the API ML SSO capability, you should omit username and password in service profiles so that the token in the base profile is used." - examples: - - - description: 'Log in to an API ML instance to obtain or update the token stored in your base profile' - options: "" - - - description: 'Log in to an API ML instance to obtain a token without storing it in a profile' - options: '--show-token' - options: - - - name: host - aliases: - - H - description: 'Host name of service on the mainframe.' - type: string - group: 'Base Connection Options' - - - name: port - aliases: - - P - description: 'Port number of service on the mainframe.' - type: number - group: 'Base Connection Options' - - - name: user - aliases: - - u - description: 'User name to authenticate to service on the mainframe.' - type: string - group: 'Base Connection Options' - - - name: password - aliases: - - pass - - pw - description: 'Password to authenticate to service on the mainframe.' - type: string - group: 'Base Connection Options' - - - name: reject-unauthorized - aliases: - - ru - description: 'Reject self-signed certificates.' - type: boolean - defaultValue: true - group: 'Base Connection Options' - - - name: cert-file - description: 'The file path to a certificate file to use for authentication' - type: existingLocalFile - group: 'Base Connection Options' - aliases: [] - - - name: cert-key-file - description: 'The file path to a certificate key file to use for authentication' - type: existingLocalFile - group: 'Base Connection Options' - aliases: [] - logout: - summary: 'Log out of API ML authentication service' - description: 'Log out of the Zowe API Mediation Layer authentication service and revoke the token so it can no longer authenticate. Also remove the token from the default base profile, if it is stored on disk.' - examples: - - - description: 'Log out of an API ML instance to revoke the token that was in use and remove it from your base profile' - options: "" - - - description: 'Log out of an API ML instance to revoke a token that was not stored in a profile' - options: '--token-value ' - options: - - - name: host - aliases: - - H - description: 'Host name of service on the mainframe.' - type: string - group: 'Base Connection Options' - - - name: port - aliases: - - P - description: 'Port number of service on the mainframe.' - type: number - group: 'Base Connection Options' - - - name: token-type - aliases: - - tt - description: 'The type of token to get and use for the API. Omit this option to use the default token type, which is provided by ''zowe auth login''.' - type: string - group: 'Base Connection Options' - allowableValues: - values: - - '^apimlAuthenticationToken.*' - - jwtToken - - LtpaToken2 - - - name: token-value - aliases: - - tv - description: 'The value of the token to pass to the API.' - type: string - group: 'Base Connection Options' - - - name: reject-unauthorized - aliases: - - ru - description: 'Reject self-signed certificates.' - type: boolean - defaultValue: true - group: 'Base Connection Options' diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/fakeBaseProfile.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/fakeBaseProfile.yaml deleted file mode 100644 index de51124255..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/base/fakeBaseProfile.yaml +++ /dev/null @@ -1 +0,0 @@ -host: fake diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/ssh/ssh_meta.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/ssh/ssh_meta.yaml deleted file mode 100644 index 4d1813374a..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/ssh/ssh_meta.yaml +++ /dev/null @@ -1,96 +0,0 @@ -defaultProfile: null -configuration: - type: ssh - schema: - type: object - title: 'z/OS SSH Profile' - description: 'z/OS SSH Profile' - properties: - host: - type: string - optionDefinition: - name: host - aliases: - - H - description: 'The z/OS SSH server host name.' - type: string - required: false - group: 'z/OS Ssh Connection Options' - port: - type: number - optionDefinition: - name: port - aliases: - - P - description: 'The z/OS SSH server port.' - type: number - defaultValue: 22 - group: 'z/OS Ssh Connection Options' - includeInTemplate: true - user: - type: string - secure: true - optionDefinition: - name: user - aliases: - - u - description: 'Mainframe user name, which can be the same as your TSO login.' - type: string - required: false - group: 'z/OS Ssh Connection Options' - password: - type: string - secure: true - optionDefinition: - name: password - aliases: - - pass - - pw - description: 'Mainframe password, which can be the same as your TSO password.' - type: string - group: 'z/OS Ssh Connection Options' - privateKey: - type: string - optionDefinition: - name: privateKey - aliases: - - key - - pk - description: 'Path to a file containing your private key, that must match a public key stored in the server for authentication' - type: string - group: 'z/OS Ssh Connection Options' - keyPassphrase: - type: string - secure: true - optionDefinition: - name: keyPassphrase - aliases: - - passphrase - - kp - description: 'Private key passphrase, which unlocks the private key.' - type: string - group: 'z/OS Ssh Connection Options' - handshakeTimeout: - type: number - optionDefinition: - name: handshakeTimeout - aliases: - - timeout - - to - description: 'How long in milliseconds to wait for the SSH handshake to complete.' - type: number - group: 'z/OS Ssh Connection Options' - required: [] - createProfileExamples: - - - options: 'ssh111 --host sshhost --user ibmuser --password myp4ss' - description: 'Create a ssh profile called ''ssh111'' to connect to z/OS SSH server at host ''zos123'' and default port 22' - - - options: 'ssh222 --host sshhost --port 13022 --user ibmuser --password myp4ss' - description: 'Create a ssh profile called ''ssh222'' to connect to z/OS SSH server at host ''zos123'' and port 13022' - - - options: 'ssh333 --host sshhost --user ibmuser --privateKey /path/to/privatekey --keyPassphrase privateKeyPassphrase' - description: 'Create a ssh profile called ''ssh333'' to connect to z/OS SSH server at host ''zos123'' using a privatekey ''/path/to/privatekey'' and its decryption passphrase ''privateKeyPassphrase'' for privatekey authentication' - - - options: 'ssh444 --privateKey /path/to/privatekey' - description: 'Create a ssh profile called ''ssh444'' to connect to z/OS SSH server on default port 22, without specifying username, host, or password, preventing those values from being stored on disk' diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/tso/tso_meta.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/tso/tso_meta.yaml deleted file mode 100644 index fc0041bd86..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/tso/tso_meta.yaml +++ /dev/null @@ -1,94 +0,0 @@ -defaultProfile: null -configuration: - type: tso - schema: - type: object - title: 'TSO Profile' - description: 'z/OS TSO/E User Profile' - properties: - account: - type: string - optionDefinition: - name: account - aliases: - - a - description: 'Your z/OS TSO/E accounting information.' - type: string - required: false - group: 'TSO ADDRESS SPACE OPTIONS' - includeInTemplate: true - characterSet: - type: string - optionDefinition: - name: character-set - aliases: - - cs - description: 'Character set for address space to convert messages and responses from UTF-8 to EBCDIC.' - type: string - defaultValue: '697' - group: 'TSO ADDRESS SPACE OPTIONS' - codePage: - type: string - optionDefinition: - name: code-page - aliases: - - cp - description: 'Codepage value for TSO/E address space to convert messages and responses from UTF-8 to EBCDIC.' - type: string - defaultValue: '1047' - group: 'TSO ADDRESS SPACE OPTIONS' - includeInTemplate: true - columns: - type: number - optionDefinition: - name: columns - aliases: - - cols - description: 'The number of columns on a screen.' - type: number - defaultValue: 80 - group: 'TSO ADDRESS SPACE OPTIONS' - logonProcedure: - type: string - optionDefinition: - name: logon-procedure - aliases: - - l - description: 'The logon procedure to use when creating TSO procedures on your behalf.' - type: string - defaultValue: IZUFPROC - group: 'TSO ADDRESS SPACE OPTIONS' - includeInTemplate: true - regionSize: - type: number - optionDefinition: - name: region-size - aliases: - - rs - description: 'Region size for the TSO/E address space.' - type: number - defaultValue: 4096 - group: 'TSO ADDRESS SPACE OPTIONS' - rows: - type: number - optionDefinition: - name: rows - description: 'The number of rows on a screen.' - type: number - defaultValue: 24 - group: 'TSO ADDRESS SPACE OPTIONS' - required: [] - createProfileExamples: - - - description: 'Create a tso profile called ''myprof'' with default settings and JES accounting information of ''IZUACCT''' - options: 'myprof -a IZUACCT' - - - description: 'Create a tso profile called ''largeregion'' with a region size of 8192, a logon procedure of MYPROC, and JES accounting information of ''1234''' - options: 'largeregion -a 1234 --rs 8192' - - - description: 'Create a tso profile called ''myprof2'' with default settings and region size of 8192, without storing the user account on disk' - options: 'myprof2 --rs 8192' - updateProfileExamples: - - - description: 'Update a tso profile called myprof with new JES accounting information' - options: 'myprof -a NEWACCT' diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/fakeServiceProfile.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/fakeServiceProfile.yaml deleted file mode 100644 index de51124255..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/fakeServiceProfile.yaml +++ /dev/null @@ -1 +0,0 @@ -host: fake diff --git a/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/zosmf_meta.yaml b/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/zosmf_meta.yaml deleted file mode 100644 index a0fc53b9bf..0000000000 --- a/packages/core/__tests__/utils/__integration__/__resources__/profiles/zosmf/zosmf_meta.yaml +++ /dev/null @@ -1,139 +0,0 @@ -defaultProfile: fakeServiceProfile -configuration: - type: zosmf - schema: - type: object - title: 'z/OSMF Profile' - description: 'z/OSMF Profile' - properties: - host: - type: string - optionDefinition: - name: host - aliases: - - H - description: 'The z/OSMF server host name.' - type: string - required: false - group: 'Zosmf Connection Options' - port: - type: number - optionDefinition: - name: port - aliases: - - P - description: 'The z/OSMF server port.' - type: number - defaultValue: 443 - group: 'Zosmf Connection Options' - includeInTemplate: true - user: - type: string - secure: true - optionDefinition: - name: user - aliases: - - u - description: 'Mainframe (z/OSMF) user name, which can be the same as your TSO login.' - type: string - required: false - group: 'Zosmf Connection Options' - password: - type: string - secure: true - optionDefinition: - name: password - aliases: - - pass - - pw - description: 'Mainframe (z/OSMF) password, which can be the same as your TSO password.' - type: string - required: false - group: 'Zosmf Connection Options' - rejectUnauthorized: - type: boolean - optionDefinition: - name: reject-unauthorized - aliases: - - ru - description: 'Reject self-signed certificates.' - type: boolean - defaultValue: true - group: 'Zosmf Connection Options' - certFile: - type: string - optionDefinition: - name: cert-file - description: 'The file path to a certificate file to use for authentication' - type: existingLocalFile - group: 'Zosmf Connection Options' - certKeyFile: - type: string - optionDefinition: - name: cert-key-file - description: 'The file path to a certificate key file to use for authentication' - type: existingLocalFile - group: 'Zosmf Connection Options' - basePath: - type: string - optionDefinition: - name: base-path - aliases: - - bp - description: 'The base path for your API mediation layer instance. Specify this option to prepend the base path to all z/OSMF resources when making REST requests. Do not specify this option if you are not using an API mediation layer.' - type: string - group: 'Zosmf Connection Options' - protocol: - type: string - optionDefinition: - name: protocol - description: 'The protocol used (HTTP or HTTPS)' - type: string - defaultValue: https - group: 'Zosmf Connection Options' - allowableValues: - values: - - http - - https - caseSensitive: false - encoding: - type: string - optionDefinition: - name: encoding - aliases: - - ec - description: 'The encoding for download and upload of z/OS data set and USS files. The default encoding if not specified is IBM-1047.' - type: string - responseTimeout: - type: number - optionDefinition: - name: response-timeout - aliases: - - rto - description: 'The maximum amount of time in seconds the z/OSMF Files TSO servlet should run before returning a response. Any request exceeding this amount of time will be terminated and return an error. Allowed values: 5 - 600' - type: number - defaultValue: null - numericValueRange: - - 5 - - 600 - required: [] - createProfileExamples: - - - options: 'zos123 --host zos123 --port 1443 --user ibmuser --password myp4ss' - description: 'Create a zosmf profile called ''zos123'' to connect to z/OSMF at host zos123 and port 1443' - - - options: 'zos124 --host zos124 --user ibmuser --password myp4ss --reject-unauthorized false' - description: 'Create a zosmf profile called ''zos124'' to connect to z/OSMF at the host zos124 (default port - 443) and allow self-signed certificates' - - - options: 'zos125 --host zos125 --port 1443' - description: 'Create a zosmf profile called ''zos125'' to connect to z/OSMF at the host zos125 and port 1443, not specifying a username or password so they are not stored on disk; these will need to be specified on every command' - - - options: 'zos126 --reject-unauthorized false' - description: 'Create a zosmf profile called ''zos126'' to connect to z/OSMF on the default port 443 and allow self-signed certificates, not specifying a username, password, or host so they are not stored on disk; these will need to be specified on every command' - - - options: 'zosAPIML --host zosAPIML --port 7554 --user ibmuser --password myp4ss --reject-unauthorized false --base-path ibmzosmf/api/v1' - description: 'Create a zosmf profile called ''zosAPIML'' to connect to z/OSMF via the Zowe API Mediation Layer running at host ''zosAPIML'', port ''7554'', and allow for self-signed certificates. To reduce duplication, you could elect to store the ''host'', ''port'', ''reject-unauthorized'', ''user'', and ''password'' values for the API Mediation Layer in a base profile and only store the ''base-path'' of the service in the zosmf profile' - updateProfileExamples: - - - options: 'zos123 --user newuser --password newp4ss' - description: 'Update a zosmf profile named ''zos123'' with a new username and password' diff --git a/packages/core/__tests__/utils/__integration__/__scripts__/copy_profiles.sh b/packages/core/__tests__/utils/__integration__/__scripts__/copy_profiles.sh deleted file mode 100755 index 6433715ec5..0000000000 --- a/packages/core/__tests__/utils/__integration__/__scripts__/copy_profiles.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# copy pre-existing profiles to test directory -cp -r $myScriptDir/../__resources__/profiles profiles -exitOnFailure "Failed to copy test profile." $? diff --git a/packages/core/__tests__/utils/__unit__/ProfileUtils.unit.test.ts b/packages/core/__tests__/utils/__unit__/ProfileUtils.unit.test.ts deleted file mode 100644 index 49a3dce17e..0000000000 --- a/packages/core/__tests__/utils/__unit__/ProfileUtils.unit.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import * as ProfileUtils from "../../../src/utils/ProfileUtils"; -import { ImperativeConfig, EnvironmentalVariableSettings, CliProfileManager, ImperativeError } from "@zowe/imperative"; -import * as os from "os"; -import * as path from "path"; - -describe("ProfileUtils", () => { - afterEach(() => { - jest.restoreAllMocks(); - }); - - describe("getZoweDir", () => { - const expectedLoadedConfig = { - name: "zowe", - defaultHome: path.join("z", "zowe"), - envVariablePrefix: "ZOWE" - }; - let defaultHome: string; - - beforeEach(() => { - jest.spyOn(EnvironmentalVariableSettings, "read").mockReturnValue({ cliHome: { value: null } } as any); - ImperativeConfig.instance.loadedConfig = undefined as any; - jest.spyOn(os, "homedir").mockReturnValue(expectedLoadedConfig.defaultHome); - defaultHome = path.join(expectedLoadedConfig.defaultHome, ".zowe"); - }); - - it("should return the ENV cliHome even if loadedConfig is set in the process", () => { - jest.spyOn(EnvironmentalVariableSettings, "read").mockReturnValue({ cliHome: { value: "test" } } as any); - expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); - expect(ProfileUtils.getZoweDir()).toEqual("test"); - expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); - }); - - it("should return the defaultHome and set loadedConfig if undefined", () => { - expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); - expect(ProfileUtils.getZoweDir()).toEqual(defaultHome); - expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); - }); - - it("should return the defaultHome and reset loadedConfig if defaultHome changes", () => { - expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); - ImperativeConfig.instance.loadedConfig = { ...expectedLoadedConfig, defaultHome: "test" }; - expect(ImperativeConfig.instance.loadedConfig?.defaultHome).toEqual("test"); - expect(ProfileUtils.getZoweDir()).toEqual(defaultHome); - expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); - }); - - it("should return the defaultHome without resetting loadedConfig", () => { - expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); - ImperativeConfig.instance.loadedConfig = expectedLoadedConfig; - expect(ProfileUtils.getZoweDir()).toEqual(defaultHome); - expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); - }); - }); - - describe("getDefaultProfile", () => { - it("should throw an error if the CLIProfileManager fails to load a profile", async () => { - jest.spyOn(CliProfileManager.prototype, "load").mockRejectedValueOnce("failed to load a profile"); - let caughtError; - try { - await ProfileUtils.getDefaultProfile("test"); - } catch (err) { - caughtError = err; - } - - expect(caughtError).toBeInstanceOf(ImperativeError); - expect(caughtError.message).toContain("Failed to load default profile"); - }); - }); -}); diff --git a/packages/core/src/constants/Core.constants.ts b/packages/core/src/constants/Core.constants.ts index 17b427dcdf..b99d57e7e5 100644 --- a/packages/core/src/constants/Core.constants.ts +++ b/packages/core/src/constants/Core.constants.ts @@ -381,33 +381,6 @@ export class ProfileConstants { } }, required: [] - }, - createProfileExamples: [ - { - options: "base1 --host example.com --port 443 --user admin --password 123456", - description: "Create a profile called 'base1' to connect to host example.com and port 443" - }, - { - options: "base2 --host example.com --user admin --password 123456 --reject-unauthorized false", - description: "Create a profile called 'base2' to connect to host example.com (default port - 443) " + - "and allow self-signed certificates" - }, - { - options: "base3 --host example.com --port 1443", - description: "Create a profile called 'base3' to connect to host example.com and port 1443, " + - " not specifying a username or password so they are not stored on disk; these will need to be specified on every command" - }, - { - options: "base4 --reject-unauthorized false", - description: "Create a zosmf profile called 'base4' to connect to default port 443 and allow self-signed certificates, " + - "not specifying a username, password, or host so they are not stored on disk; these will need to be specified on every command" - } - ], - updateProfileExamples: [ - { - options: "base1 --user newuser --password newp4ss", - description: "Update a base profile named 'base1' with a new username and password" - } - ] + } }; } diff --git a/packages/core/src/utils/ProfileUtils.ts b/packages/core/src/utils/ProfileUtils.ts deleted file mode 100644 index 027e6c0325..0000000000 --- a/packages/core/src/utils/ProfileUtils.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ImperativeConfig, IProfileLoaded, CliProfileManager, IProfile, Logger, ImperativeError } from "@zowe/imperative"; -import * as path from "path"; -import * as os from "os"; - -/** - * Retrieves the Zowe CLI home directory. In the situation Imperative has - * not initialized it we mock a default value. - * @returns {string} - Returns the Zowe home directory - */ -export function getZoweDir(): string { - const defaultHome = path.join(os.homedir(), ".zowe"); - if (ImperativeConfig.instance.loadedConfig?.defaultHome !== defaultHome) { - ImperativeConfig.instance.loadedConfig = { - name: "zowe", - defaultHome, - envVariablePrefix: "ZOWE" - }; - } - return ImperativeConfig.instance.cliHome; -} - -/** - * Loads default z/OSMF profile. The profile must have already been - * created using Zowe CLI, and not rely on base profiles - * - * @param {string} profileType - The name of the profile type - * @param {boolean} mergeWithBase - Whether or not to merge with the base profile - * @returns {IProfile} - The default profile (or merged profile, if requested) - */ -export async function getDefaultProfile(profileType: string, mergeWithBase?: boolean) { - - const profileRootDir: string = path.join(getZoweDir(), "profiles"); - const logger: Logger = Logger.getImperativeLogger(); - let profileManager: CliProfileManager; - let profileLoaded: IProfileLoaded; - - try { - // Create the profile manager - profileManager = new CliProfileManager({ - profileRootDirectory: profileRootDir, - type: profileType - }); - - // Load the profile using the profile manager - profileLoaded = await profileManager.load({ - loadDefault: true - }); - } catch (err) { - logger.warn(err.message); - } - - // Throw an error if there was no default profile found and no base profile requested - if ((!profileLoaded || !profileLoaded.profile) && !mergeWithBase) { - throw new ImperativeError({msg: `Failed to load default profile of type "${profileType}"`}); - } - - // Give the profile back as-is if the profile is not to be merged with the base profile - if (mergeWithBase === false) { - return profileLoaded.profile; - } - - let baseProfileManager: CliProfileManager; - let baseProfileLoaded: IProfileLoaded; - - try { - baseProfileManager = new CliProfileManager({ - profileRootDirectory: profileRootDir, - type: "base" - }); - - baseProfileLoaded = await baseProfileManager.load({ - loadDefault: true - }); - } catch (err) { - logger.warn(err.message); - } - - // Return service profile if there was no base profile found and service profile existed. - // Return base profile if there was no service profile found and base profile existed. - // If both exist, combine. Otherwise, error - if ((!baseProfileLoaded || !baseProfileLoaded.profile) && (profileLoaded && profileLoaded.profile)) { - return profileLoaded.profile; - } else if (baseProfileLoaded && baseProfileLoaded.profile && (!profileLoaded || !profileLoaded.profile)) { - return baseProfileLoaded.profile; - } else if ((!baseProfileLoaded || !baseProfileLoaded.profile) && (!profileLoaded || !profileLoaded.profile)) { - throw new ImperativeError({msg: `Failed to load default profiles of types "${profileType}" and "base"`}); - } - - const combinedProfile: IProfile = JSON.parse(JSON.stringify(baseProfileLoaded.profile)); - - for (const propertyName in profileLoaded.profile) { - if (profileLoaded.profile[propertyName] != null) { - combinedProfile[propertyName] = profileLoaded.profile[propertyName]; - } - } - - return combinedProfile; -} \ No newline at end of file diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts index 0da3c75968..a3f1390ef9 100644 --- a/packages/core/src/utils/index.ts +++ b/packages/core/src/utils/index.ts @@ -11,4 +11,3 @@ export * from "./CoreUtils"; export * from "./CommonConstants"; -export * from "./ProfileUtils"; diff --git a/packages/imperative/CHANGELOG.md b/packages/imperative/CHANGELOG.md index d1ec4797e3..2c4eb57c45 100644 --- a/packages/imperative/CHANGELOG.md +++ b/packages/imperative/CHANGELOG.md @@ -5,6 +5,186 @@ All notable changes to the Imperative package will be documented in this file. ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- BugFix: Removed `profileVersion` from the response given by `--show-inputs-only` to fix [#1689](https://github.com/zowe/zowe-cli/issues/1689). Extended that change to the `config report-env` command, where similar soon-to-be obsolete v1 considerations occur. +- BugFix: Changed text displayed for configuration from "V2" to "TeamConfig" [#2019](https://github.com/zowe/zowe-cli/issues/2019) +- BugFix: Eliminated a Node Version Manager (NVM) GUI popup dialog which NVM now displays during the `zowe config report-env` command by removing the NVM version number from our report. +- Enhancement: Replaced the term "Team configuration" with "Zowe client configuration" in the `zowe config report-env` command. + +- LTS Breaking: [#1703](https://github.com/zowe/zowe-cli/issues/1703) + - Removed the following obsolete V1 profile interfaces: + - @zowe/cli-test-utils + - ISetupEnvironmentParms.createOldProfiles + + - @zowe/imperative + - ICliLoadProfile + - ICliLoadAllProfiles + - ICommandLoadProfile + - ICommandProfileTypeConfiguration.createProfileExamples + - ICommandProfileTypeConfiguration.createProfileFromArgumentsHandler + - ICommandProfileTypeConfiguration.updateProfileExamples + - ICommandProfileTypeConfiguration.updateProfileFromArgumentsHandler + - IDeleteProfile + - ILoadAllProfiles + - ILoadProfile + - IProfileDeleted + - IProfileManager.loadCounter + - IProfileManagerFactory + - IProfileSaved + - IProfileValidated + - ISaveProfile + - ISaveProfileFromCliArgs + - ISetDefaultProfile + - IUpdateProfile + - IUpdateProfileFromCliArgs + - IValidateProfile + - IValidateProfileForCLI + - IValidateProfileWithSchema + + - Removed the following obsolete V1 profile classes/functions: + - @zowe/core-for-zowe-sdk + - File ProfileUtils.ts, which includes these functions: + - getDefaultProfile + - getZoweDir - moved to ProfileInfo.getZoweDir + + - @zowe/cli-test-utils + - TempTestProfiles.forceOldProfiles + - TestUtils.stripProfileDeprecationMessages + + - @zowe/imperative + - AbstractProfileManager + - Any remaining functions consolidated into CliProfileManager + - AbstractProfileManagerFactory + - BasicProfileManager + - Any remaining functions consolidated into CliProfileManager + - BasicProfileManagerFactory + - CliProfileManager + - clearDefault + - configurations + - constructFullProfilePath + - delete + - deleteProfile + - deleteProfileFromDisk + - getAllProfileNames + - getDefaultProfileName + - isProfileEmpty + - load + - loadAll + - loadCounter + - loadDependencies + - loadFailed + - loadProfile + - loadSpecificProfile + - locateExistingProfile + - managerParameters + - mergeProfiles + - META_FILE_SUFFIX + - PROFILE_EXTENSION + - profileRootDirectory + - profileTypeSchema + - save + - saveProfile + - setDefault + - update + - updateProfile + - validate + - validateProfile + - validateProfileAgainstSchema + - validateProfileObject + - validateRequiredDependenciesAreSpecified + - CommandProfiles + - getMeta + - getAll + - ImperativeProfileManagerFactory + - ProfileInfo.usingTeamConfig + - To detect if a team config exists, use ProfileInfo.getTeamConfig + - To detect if only V1 profiles exist, use ProfileInfo.onlyV1ProfilesExist + + - @zowe/zos-uss-for-zowe-sdk + - SshBaseHandler + - Removed the unused, protected property ‘mSshProfile’ + + - Removed the following obsolete V1 profile constants: + - @zowe/imperative + - CoreMessages class + - createProfileCommandSummary + - createProfileDisableDefaultsDesc + - createProfileOptionDesc + - createProfileOptionOverwriteDesc + - createProfilesCommandDesc + - createProfilesCommandSummary + - deleteProfileActionDesc + - deleteProfileCommandDesc + - deleteProfileDepsDesc + - deleteProfileExample + - deleteProfileForceOptionDesc + - deleteProfileNameDesc + - deleteProfilesCommandDesc + - deleteProfilesCommandSummary + - detailProfileCommandDesc + - listGroupWithOnlyProfileCommandSummary + - listGroupWithOnlyProfileDefaultDesc + - listGroupWithOnlyProfilesDefinition + - listGroupWithOnlyProfileSetDesc + - listGroupWithOnlyProfilesSummary + - listProfileCommandDesc + - listProfileCommandSummary + - listProfileExample + - listProfileExampleShowContents + - listProfileLoadedModulesOptionDesc + - listProfilesFoundMessage + - listProfilesNotFoundMessage + - listProfileVerboseOptionDesc + - locateProfilesDesc + - overroteProfileMessage + - profileCreatedSuccessfully + - profileCreatedSuccessfullyAndPath + - profileCreateErrorDetails + - profileCreateErrorHeader + - profileDeletedSuccessfully + - profileDeleteErrorDetails + - profileDeleteErrorHeader + - profileDesc + - profileLoadError + - profileNotDeletedMessage + - profileReviewMessage + - profileUpdatedSuccessfullyAndPath + - selectProfileNameDesc + - setGroupWithOnlyProfilesCommandDesc + - setGroupWithOnlyProfilesListDesc + - setGroupWithOnlyProfilesSummary + - setProfileActionDesc + - setProfileActionSummary + - setProfileExample + - setProfileOptionDesc + - showDependenciesCommandDesc + - unableToCreateProfile + - unableToDeleteProfile + - unableToFindProfile + - unableToLoadRequestedProfilesError + - unexpectedProfileCreationError + - unexpectedProfileLoadError + - unexpectedProfilesLoadError + - unexpectedProfileUpdateError + - updateProfileActionDesc + - updateProfileCommandDesc + - updateProfileCommandSummary + - validateProfileCommandDesc + - validateProfileCommandSummary + - validateProfileGroupDesc + - validateProfileNameDesc + - validateProfileOptionDesc + - ProfilesConstants class + - DEPRECATE_TO_CONFIG_EDIT + - DEPRECATE_TO_CONFIG_INIT + - DEPRECATE_TO_CONFIG_LIST + - DEPRECATE_TO_CONFIG_SET + - PROFILES_COMMAND_TYPE_KEY + + - Annotated the following items as @internal: + - @zowe/imperative + - CommandProfileLoader + - ImperativeApi.profileManager + - ProfileValidator ## `8.0.0-next.202402271901` diff --git a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/Cmd.cli.read.profile.integration.test.ts b/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/Cmd.cli.read.profile.integration.test.ts deleted file mode 100644 index 940cf53bc7..0000000000 --- a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/Cmd.cli.read.profile.integration.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { runCliScript } from "../../../../../../src/TestUtil"; -import { ITestEnvironment } from "../../../../../../__src__/environment/doc/response/ITestEnvironment"; -import { SetupTestEnvironment } from "../../../../../../__src__/environment/SetupTestEnvironment"; -// Test Environment populated in the beforeAll(); -let TEST_ENVIRONMENT: ITestEnvironment; -describe("cmd-cli profiles read profiles", () => { - // Create the unique test environment - beforeAll(async () => { - TEST_ENVIRONMENT = await SetupTestEnvironment.createTestEnv({ - cliHomeEnvVar: "CMD_CLI_CLI_HOME", - testName: "cmd_read_profiles" - }); - }); - - it("should read a profile with a secure field stored in plain text and be able to read the contents", () => { - const response = runCliScript(__dirname + "/__scripts__/profile/create_and_read.sh", TEST_ENVIRONMENT.workingDir); - expect(response.stderr.toString()).toBe(""); - expect(response.stdout.toString()).toContain("info: some info"); - expect(response.stdout.toString()).toContain("secret: not so secret info"); - expect(response.stdout.toString()).not.toContain("managed by"); - expect(response.status).toBe(0); - }); -}); diff --git a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/insecure_meta.yaml b/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/insecure_meta.yaml deleted file mode 100644 index d1b55364ae..0000000000 --- a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/insecure_meta.yaml +++ /dev/null @@ -1,30 +0,0 @@ -defaultProfile: test_insecure -configuration: - type: insecure - schema: - type: object - title: 'insecure Profile' - description: 'insecure Profile' - properties: - info: - type: string - optionDefinition: - name: info - aliases: - - i - description: 'The info property.' - type: string - required: false - group: 'insecure group' - secret: - type: string - secure: true - optionDefinition: - name: secret - aliases: - - s - description: 'The secret property.' - type: string - required: false - group: 'insecure group' - required: [] diff --git a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/test_insecure.yaml b/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/test_insecure.yaml deleted file mode 100644 index a5125f379a..0000000000 --- a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/__resources__/profiles/insecure/test_insecure.yaml +++ /dev/null @@ -1,2 +0,0 @@ -info: some info -secret: not so secret info diff --git a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/profile/create_and_read.sh b/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/profile/create_and_read.sh deleted file mode 100644 index 3e25d4c778..0000000000 --- a/packages/imperative/__tests__/__integration__/cmd/__tests__/integration/cli/read/__scripts__/profile/create_and_read.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# copy pre-existing profiles to test directory -cp -r $myScriptDir/../__resources__/profiles profiles -exitOnFailure "Failed to copy test profile." $? - -# read the profile and display its information -cmd-cli read profile -exitOnFailure "Failed display profile." $? diff --git a/packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/report-env/cli.imperative-test-cli.config.report-env.integration.test.ts b/packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/report-env/cli.imperative-test-cli.config.report-env.integration.test.ts index 6088da71eb..05622f601d 100644 --- a/packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/report-env/cli.imperative-test-cli.config.report-env.integration.test.ts +++ b/packages/imperative/__tests__/__integration__/imperative/__tests__/__integration__/cli/config/report-env/cli.imperative-test-cli.config.report-env.integration.test.ts @@ -86,7 +86,6 @@ describe("imperative-test-cli config report-env", () => { expect(response.error).toBeFalsy(); expect(response.output.toString()).toContain("Zowe CLI version ="); expect(response.output.toString()).toContain("Node.js version ="); - expect(response.output.toString()).toContain("Node Version Manager version ="); expect(response.output.toString()).toContain("O.S. platform ="); expect(response.output.toString()).toContain("O.S. architecture ="); expect(response.output.toString()).toContain("O.S. PATH ="); @@ -101,8 +100,7 @@ describe("imperative-test-cli config report-env", () => { expect(response.output.toString()).toContain("HOME ="); expect(response.output.toString()).toContain("Zowe CLI configuration information"); expect(response.output.toString()).toContain("Zowe daemon mode ="); - expect(response.output.toString()).toContain("Zowe config type = V2 Team Config"); - expect(response.output.toString()).toContain("Team config files in effect:"); + expect(response.output.toString()).toContain("Zowe client config files in use:"); expect(response.output.toString()).toContain("imperative-test-cli.config.json"); expect(response.output.toString()).toContain("Default profile names:"); expect(response.output.toString()).toContain("base = myBase"); @@ -143,7 +141,6 @@ describe("imperative-test-cli config report-env", () => { expect(response.error).toBeFalsy(); expect(response.stdout.toString()).toContain("Zowe CLI version ="); expect(response.stdout.toString()).toContain("Node.js version ="); - expect(response.stdout.toString()).toContain("Node Version Manager version ="); expect(response.stdout.toString()).toContain("O.S. platform ="); expect(response.stdout.toString()).toContain("O.S. architecture ="); expect(response.stdout.toString()).toContain("O.S. PATH ="); @@ -159,8 +156,7 @@ describe("imperative-test-cli config report-env", () => { expect(response.stdout.toString()).toContain("HOME ="); expect(response.stdout.toString()).toContain("Zowe CLI configuration information"); expect(response.stdout.toString()).toContain("Zowe daemon mode ="); - expect(response.stdout.toString()).toContain("Zowe config type = V2 Team Config"); - expect(response.stdout.toString()).toContain("Team config files in effect:"); + expect(response.stdout.toString()).toContain("Zowe client config files in use:"); expect(response.stdout.toString()).toContain("imperative-test-cli.config.json"); expect(response.stdout.toString()).toContain("Default profile names:"); expect(response.stdout.toString()).toContain("base = myBase"); @@ -203,7 +199,6 @@ describe("imperative-test-cli config report-env", () => { expect(response.error).toBeFalsy(); expect(response.stdout.toString()).toContain("Zowe CLI version ="); expect(response.stdout.toString()).toContain("Node.js version ="); - expect(response.stdout.toString()).toContain("Node Version Manager version ="); expect(response.stdout.toString()).toContain("O.S. platform ="); expect(response.stdout.toString()).toContain("O.S. architecture ="); expect(response.stdout.toString()).toContain("O.S. PATH ="); @@ -219,8 +214,7 @@ describe("imperative-test-cli config report-env", () => { expect(response.stdout.toString()).toContain("HOME ="); expect(response.stdout.toString()).toContain("Zowe CLI configuration information"); expect(response.stdout.toString()).toContain("Zowe daemon mode ="); - expect(response.stdout.toString()).toContain("Zowe config type = V2 Team Config"); - expect(response.stdout.toString()).toContain("Team config files in effect:"); + expect(response.stdout.toString()).toContain("Zowe client config files in use:"); expect(response.stdout.toString()).toContain("imperative-test-cli.config.json"); expect(response.stdout.toString()).toContain("Default profile names:"); expect(response.stdout.toString()).toContain("base = myBase"); @@ -264,7 +258,6 @@ describe("imperative-test-cli config report-env", () => { expect(response.error).toBeFalsy(); expect(response.stdout.toString()).toContain("Zowe CLI version ="); expect(response.stdout.toString()).toContain("Node.js version ="); - expect(response.stdout.toString()).toContain("Node Version Manager version ="); expect(response.stdout.toString()).toContain("O.S. platform ="); expect(response.stdout.toString()).toContain("O.S. architecture ="); expect(response.stdout.toString()).toContain("O.S. PATH ="); @@ -280,8 +273,7 @@ describe("imperative-test-cli config report-env", () => { expect(response.stdout.toString()).toContain("HOME ="); expect(response.stdout.toString()).toContain("Zowe CLI configuration information"); expect(response.stdout.toString()).toContain("Zowe daemon mode ="); - expect(response.stdout.toString()).toContain("Zowe config type = V2 Team Config"); - expect(response.stdout.toString()).toContain("Team config files in effect:"); + expect(response.stdout.toString()).toContain("Zowe client config files in use:"); expect(response.stdout.toString()).toContain("imperative-test-cli.config.json"); expect(response.stdout.toString()).toContain("Default profile names:"); expect(response.stdout.toString()).toContain("base = myBase"); @@ -324,7 +316,6 @@ describe("imperative-test-cli config report-env", () => { expect(response.error).toBeFalsy(); expect(response.stdout.toString()).toContain("Zowe CLI version ="); expect(response.stdout.toString()).toContain("Node.js version ="); - expect(response.stdout.toString()).toContain("Node Version Manager version ="); expect(response.stdout.toString()).toContain("O.S. platform ="); expect(response.stdout.toString()).toContain("O.S. architecture ="); expect(response.stdout.toString()).toContain("O.S. PATH ="); @@ -341,8 +332,7 @@ describe("imperative-test-cli config report-env", () => { expect(response.stdout.toString()).toContain("HOME ="); expect(response.stdout.toString()).toContain("Zowe CLI configuration information"); expect(response.stdout.toString()).toContain("Zowe daemon mode ="); - expect(response.stdout.toString()).toContain("Zowe config type = V2 Team Config"); - expect(response.stdout.toString()).toContain("Team config files in effect:"); + expect(response.stdout.toString()).toContain("Zowe client config files in use:"); expect(response.stdout.toString()).toContain("imperative-test-cli.config.json"); expect(response.stdout.toString()).toContain("Default profile names:"); expect(response.stdout.toString()).toContain("base = myBase"); diff --git a/packages/imperative/__tests__/config/jest.preset.json b/packages/imperative/__tests__/config/jest.preset.json index 80286a736d..fda74ee2b8 100644 --- a/packages/imperative/__tests__/config/jest.preset.json +++ b/packages/imperative/__tests__/config/jest.preset.json @@ -1,14 +1,11 @@ { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsconfig": "tsconfig-tests.json" - } - }, "moduleFileExtensions": ["ts","js"], "testResultsProcessor": "jest-stare", "testEnvironment": "node", "transform": { - ".(ts)": "ts-jest" + ".(ts)": ["ts-jest", { + "diagnostics": false, + "tsconfig": "packages/imperative/tsconfig-tests.json" + }] } } \ No newline at end of file diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleCLINoAutoGen.ts b/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleCLINoAutoGen.ts deleted file mode 100644 index ebca63838d..0000000000 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleCLINoAutoGen.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IImperativeConfig, Imperative } from "../../../../src/imperative"; -// load the other config -const config: IImperativeConfig = require(__dirname + "/ProfileExampleConfiguration.ts"); -config.autoGenerateProfileCommands = false; // but turn off the auto generated commands - -Imperative.init(config).then(() => { - Imperative.parse(); -}); - diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleConfiguration.ts b/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleConfiguration.ts index a755ed08ea..3fe9563ca5 100644 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleConfiguration.ts +++ b/packages/imperative/__tests__/src/example_clis/with_profiles/ProfileExampleConfiguration.ts @@ -106,19 +106,7 @@ const config: IImperativeConfig = { } }, required: ["animal", "numberWithDefault"] - }, - createProfileExamples: [ - { - options: "--animal doggy", - description: "Create a profile-a profile with a doggy as the animal" - } - ], - updateProfileExamples: [ - { - options: "--animal froggy", - description: "Update a profile-a profile to use froggy as the animal" - } - ] + } }, { type: "profile-b", diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/WithProfiles.integration.test.ts b/packages/imperative/__tests__/src/example_clis/with_profiles/WithProfiles.integration.test.ts index 6dd621c050..0de0e5180c 100644 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/WithProfiles.integration.test.ts +++ b/packages/imperative/__tests__/src/example_clis/with_profiles/WithProfiles.integration.test.ts @@ -9,7 +9,6 @@ * */ -// These tests require access to the same values on the keyring, therefore they cannot run in parallel // The test order is important - some tests depend on other tests not running first - do not change it /* eslint-disable max-len */ diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/AutoGeneratedProfileCommands.integration.subtest.ts b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/AutoGeneratedProfileCommands.integration.subtest.ts index 9c69126465..b2772f5a17 100644 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/AutoGeneratedProfileCommands.integration.subtest.ts +++ b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/AutoGeneratedProfileCommands.integration.subtest.ts @@ -9,99 +9,23 @@ * */ -import { IImperativeConfig } from "../../../../../src/imperative"; import * as T from "../../../TestUtil"; -import * as path from "path"; -import * as fs from "fs"; describe("We should provide auto-generated profile commands for convenience, " + "so that Imperative-based CLIs can let users manage configuration profiles", () => { const cliBin = __dirname + "/../ProfileExampleCLI.ts"; - const config: IImperativeConfig = require(__dirname + "/../ProfileExampleConfiguration"); - const profileTypeA = "profile-a"; - const profileTypeB = "profile-b"; - - const manyFieldProfile = "many-field-profile"; - const env = JSON.parse(JSON.stringify(process.env)); - const home = config.defaultHome; - - beforeAll(() => { - // ensure a clean CLI home directory exists before running our copy_profile script - T.rimraf(home); - fs.mkdirSync(home); - - // copy existing profiles into test directory - const result = T.runCliScript(path.join(__dirname, "__scripts__/copy_auto_gen_profiles.sh"), home); - expect(result.stderr.toString()).toBe(""); - expect(result.status).toBe(0); - }); - - afterAll(() => { - T.rimraf(home); - }); - - it("should use a profile with a valid dependent profile", () => { + it("should fail to load a V1 dependent profile", () => { const result = T.executeTestCLICommand(cliBin, this, ["use-dependent-profile"]); - expect(result.stderr).toBe(""); - expect(result.stdout).toContain("Loaded profile dependency of type profile-a"); - expect(result.stdout).toContain("Loaded main profile of type profile-with-dependency"); - expect(result.status).toBe(0); - }); - it("should use a profile with a dependent profile that is not the default for its type", () => { - // set the default profile for type profile-a - let result: any = T.runCliScript(path.join(__dirname, "__scripts__/set_default_profile.sh"), home, - [profileTypeA, "non_existent_default_a_profile"] - ); - expect(result.stderr.toString()).toBe(""); - expect(result.status).toBe(0); - - // use a profile that has a dependency which is now NOT the default profile for that dependency - result = T.executeTestCLICommand(cliBin, this, ["use-dependent-profile"]); - expect(result.stderr).toBe(""); - expect(result.stdout).toContain(`Loaded profile dependency of type ${profileTypeA}`); - expect(result.stdout).toContain("Loaded main profile of type profile-with-dependency"); - expect(result.status).toBe(0); - }); - - it("should be able to use two types of profiles", () => { - const firstProfile = "first"; - const secondProfile = "second"; - - // set the default profile for type profile-a - let result: any = T.runCliScript(path.join(__dirname, "__scripts__/set_default_profile.sh"), home, - [profileTypeA, firstProfile] - ); - expect(result.stderr.toString()).toBe(""); - expect(result.status).toBe(0); - - // set the default profile for type profile-b - result = T.runCliScript(path.join(__dirname, "__scripts__/set_default_profile.sh"), home, - [profileTypeB, firstProfile] - ); - expect(result.stderr.toString()).toBe(""); - expect(result.status).toBe(0); - - // use both A profiles - T.findExpectedOutputInCommand(cliBin, ["use-profile-a"], - [], // default A profile - "stdout", true, this, T.CMD_TYPE.JSON, { ignoreCase: true } - ); - T.findExpectedOutputInCommand(cliBin, ["use-profile-a", "--profile-a-profile", secondProfile], - [], - "stdout", true, this, T.CMD_TYPE.JSON, { ignoreCase: true } - ); - - // use both B profiles - T.findExpectedOutputInCommand(cliBin, ["use-profile-b"], // default B profile - [], - "stdout", true, this, T.CMD_TYPE.JSON, { ignoreCase: true } - ); - T.findExpectedOutputInCommand(cliBin, ["use-profile-b", "--profile-b-profile", secondProfile], - [], - "stdout", true, this, T.CMD_TYPE.JSON, { ignoreCase: true } + /* Since we no longer read V1 profiles from disk, such an operation will always return an error. + Note that Zowe client code no longer attempts to do such an operation. + */ + expect(result.stderr).toContain( + 'Profile of type "profile-with-dependency" does not exist ' + + 'within the loaded profiles for the command and it is marked as required' ); + expect(result.status).toBe(1); }); it("should not fail a command where the profile is listed as optional and not specified", () => { diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/ExampleProfiles.integration.subtest.ts b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/ExampleProfiles.integration.subtest.ts index dd78a53156..25bdc3b950 100644 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/ExampleProfiles.integration.subtest.ts +++ b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/ExampleProfiles.integration.subtest.ts @@ -12,8 +12,7 @@ import * as T from "../../../TestUtil"; import { IImperativeConfig } from "../../../../../src/imperative"; -describe("We should provide the ability to create, manage, and use profiles, " + - "tested through an example CLI", function () { +describe("We should provide the ability access profiles from an example CLI definition", function () { const config: IImperativeConfig = require(__dirname + "/../ProfileExampleConfiguration"); it("We should be able to get --help for our example CLI", function () { diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/copy_auto_gen_profiles.sh b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/copy_auto_gen_profiles.sh deleted file mode 100644 index 911f0184f7..0000000000 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/copy_auto_gen_profiles.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# copy pre-existing profiles to test directory -cp -r $myScriptDir/../__resources__/autoGenProfiles profiles -exitOnFailure "Failed to copy test profile." $? diff --git a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/set_default_profile.sh b/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/set_default_profile.sh deleted file mode 100644 index add8385a20..0000000000 --- a/packages/imperative/__tests__/src/example_clis/with_profiles/__integration__/__scripts__/set_default_profile.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -profileType=${1:?"First parm (profileType) is required."} -defaultProfName=${2:?"Second parm (defaultProfName) is required."} - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# This script expects that pre-existing profiles have already been copied to the test directory -mv profiles/$profileType/${profileType}_meta.yaml profiles/$profileType/${profileType}_meta_orig.yaml -exitOnFailure "Failed to backup '$profileType' meta file." $? - -sed -e "s/defaultProfile:.*/defaultProfile: $defaultProfName/" \ - < profiles/$profileType/${profileType}_meta_orig.yaml > profiles/$profileType/${profileType}_meta.yaml -exitOnFailure "Failed to set default profile to '$defaultProfName' for type '$profileType'." $? diff --git a/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManager.integration.test.ts b/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManager.integration.test.ts index d616cec979..8890b9e2c5 100644 --- a/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManager.integration.test.ts +++ b/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManager.integration.test.ts @@ -9,47 +9,66 @@ * */ -jest.mock("../../../../../src/utilities/src/ImperativeConfig"); - +import * as TestUtil from "../../../TestUtil"; import { TestLogger } from "../../../../src/TestLogger"; import { CliProfileManager } from "../../../../../src/cmd/src/profiles/CliProfileManager"; import { ICommandProfileTypeConfiguration } from "../../../../../src/cmd"; +import { ProfileUtils } from "../../../../../src/profiles"; +import { ITestEnvironment } from "../../../../__src__/environment/doc/response/ITestEnvironment"; +import { SetupTestEnvironment } from "../../../../__src__/environment/SetupTestEnvironment"; +import { bananaProfile, getConfig, PROFILE_TYPE } from "./CliProfileManagerTestConstants"; + +let TEST_ENVIRONMENT: ITestEnvironment; describe("Cli Profile Manager", () => { - const profileDir = __dirname + "/__resources__/cliprofilemanager"; - const addTwoNumbersHandler = __dirname + "/../profileHandlers/AddTwoNumbersHandler"; + const mainModule = process.mainModule; const testLogger = TestLogger.getTestLogger(); const profileTypeOne = "banana"; - const getTypeConfigurations: () => ICommandProfileTypeConfiguration[] = () => { - return [{ - type: profileTypeOne, - schema: { - type: "object", - title: "test profile", - description: "test profile", - properties: { - sum: { - type: "number" - } - }, - required: ["sum"] - }, - }]; - }; + beforeAll(async () => { + (process.mainModule as any) = { + filename: __filename + }; - it("should be able to load properties from an existing profile", async () => { - const profileName = "myprofile"; - const configs = getTypeConfigurations(); - configs[0].createProfileFromArgumentsHandler = addTwoNumbersHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs + TEST_ENVIRONMENT = await SetupTestEnvironment.createTestEnv({ + cliHomeEnvVar: "CMD_CLI_CLI_HOME", + testName: "basic_profile_mgr" }); - const loadedProfile: any = await manager.load({name: profileName}); - expect(loadedProfile.profile.sum).toEqual(3); + }); + + afterAll(() => { + process.mainModule = mainModule; + TestUtil.rimraf(TEST_ENVIRONMENT.workingDir); + }); + + it("should create a profile manager", async () => { + let caughtError: Error = new Error(""); + let newProfMgr; + + try { + // Create a manager instance + newProfMgr = new CliProfileManager({ + logger: TestLogger.getTestLogger(), + type: PROFILE_TYPE.BANANA, + typeConfigurations: [bananaProfile] + }); + } catch (e) { + caughtError = e; + TestLogger.error(caughtError.message); + } + + expect(newProfMgr).not.toBeNull(); + expect(caughtError.message).toEqual(""); + }); + + it("should be able to retrieve all defined types after init", async function () { + const Imperative = require("../../../../../src/imperative/src/Imperative").Imperative; + const ImperativeConfig = require("../../../../../src/utilities/src/ImperativeConfig").ImperativeConfig; + + const config = getConfig(TEST_ENVIRONMENT.workingDir); + await Imperative.init(config); + expect(ProfileUtils.getAllTypeNames(ImperativeConfig.instance.loadedConfig.profiles).length).toEqual(Object.keys(PROFILE_TYPE).length); + expect(ProfileUtils.getAllTypeNames(ImperativeConfig.instance.loadedConfig.profiles)).toContain("banana"); }); it("should be able to automatically map command line options to " + @@ -85,7 +104,6 @@ describe("Cli Profile Manager", () => { let caughtError; try { new CliProfileManager({ - profileRootDirectory: profileDir, type: profileTypeOne, logger: testLogger, typeConfigurations: configs diff --git a/packages/imperative/__tests__/src/packages/profiles/src/constants/BasicProfileManagerTestConstants.ts b/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManagerTestConstants.ts similarity index 96% rename from packages/imperative/__tests__/src/packages/profiles/src/constants/BasicProfileManagerTestConstants.ts rename to packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManagerTestConstants.ts index d623bf9625..a7e71d764f 100644 --- a/packages/imperative/__tests__/src/packages/profiles/src/constants/BasicProfileManagerTestConstants.ts +++ b/packages/imperative/__tests__/src/packages/cmd/__integration__/CliProfileManagerTestConstants.ts @@ -9,9 +9,9 @@ * */ -import { IImperativeConfig } from "../../../../../../src/index"; -import * as TestUtils from "../../../../TestUtil"; -import { ICommandProfileTypeConfiguration } from "../../../../../../src/cmd"; +import { IImperativeConfig } from "../../../../../src/index"; +import * as TestUtils from "../../../TestUtil"; +import { ICommandProfileTypeConfiguration } from "../../../../../src/cmd"; /** * Get a config and set the home directory. diff --git a/packages/imperative/__tests__/src/packages/cmd/__integration__/SyntaxValidator.integration.test.ts b/packages/imperative/__tests__/src/packages/cmd/__integration__/SyntaxValidator.integration.test.ts index 1352a30dd7..1a375da621 100644 --- a/packages/imperative/__tests__/src/packages/cmd/__integration__/SyntaxValidator.integration.test.ts +++ b/packages/imperative/__tests__/src/packages/cmd/__integration__/SyntaxValidator.integration.test.ts @@ -19,7 +19,7 @@ import { TestLogger } from "../../../../src/TestLogger"; import { createUniqueTestDataDir, rimraf } from "../../../TestUtil"; import { AbstractHelpGenerator } from "../../../../../src/cmd/src/help/abstract/AbstractHelpGenerator"; import { DefaultHelpGenerator } from "../../../../../src/cmd/src/help/DefaultHelpGenerator"; -import { BasicProfileManagerFactory, IProfileTypeConfiguration } from "../../../../../src/index"; +import { IProfileTypeConfiguration } from "../../../../../src/index"; const ENV_PREFIX = "INTEGRATION_TEST"; const TEST_HOME = createUniqueTestDataDir(); @@ -93,7 +93,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: ValidationTestCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fakeroot", commandLine: "fakecommand", promptPhrase: "fakefakefake" @@ -450,8 +449,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: numberCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, - DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fake", commandLine: "fake", promptPhrase: "fakefakefake" @@ -481,8 +478,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: numberCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, - DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fake", commandLine: "fake", promptPhrase: "fakefakefake" @@ -535,8 +530,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: numberCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, - DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fake", commandLine: "fake", promptPhrase: "dummydummy" @@ -569,8 +562,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: numberCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, - DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fake", commandLine: "fake", promptPhrase: "fakefakefake" @@ -600,8 +591,6 @@ describe("Imperative should provide advanced syntax validation rules", function definition: numberCommand, fullDefinition: fakeParent, helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(TEST_HOME, - DUMMY_PROFILE_TYPE_CONFIG), rootCommandName: "fake", commandLine: "fake", promptPhrase: "dummydummy" diff --git a/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/banana_meta.yaml b/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/banana_meta.yaml deleted file mode 100644 index 86386d562b..0000000000 --- a/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/banana_meta.yaml +++ /dev/null @@ -1,13 +0,0 @@ -defaultProfile: myprofile -configuration: - type: banana - schema: - type: object - title: 'test profile' - description: 'test profile' - properties: - sum: - type: number - required: - - sum - createProfileFromArgumentsHandler: /home/stduser/repos/zowe-cli/packages/imperative/__tests__/src/packages/cmd/__integration__/../profileHandlers/AddTwoNumbersHandler diff --git a/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/myprofile.yaml b/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/myprofile.yaml deleted file mode 100644 index 79a6a4662a..0000000000 --- a/packages/imperative/__tests__/src/packages/cmd/__integration__/__resources__/cliprofilemanager/banana/myprofile.yaml +++ /dev/null @@ -1 +0,0 @@ -sum: 3 diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.constructor.integration.test.ts b/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.constructor.integration.test.ts deleted file mode 100644 index 2c26f2a4b0..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.constructor.integration.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../../../src/utilities/src/ImperativeConfig"); - -import * as TestUtil from "../../../TestUtil"; -import { BasicProfileManager } from "../../../../../src/index"; -import { TestLogger } from "../../../../src/TestLogger"; -import { bananaProfile, PROFILE_TYPE } from "../src/constants/BasicProfileManagerTestConstants"; - -const profileDirectory = TestUtil.createUniqueTestDataDir("profile-manager-initialize"); - -describe("Basic Profile Manager Constructor", () => { - it("Should create a profile manager", async () => { - let caughtError: Error = new Error(""); - let newProfMgr; - - try { - // Create a manager instance - newProfMgr = new BasicProfileManager({ - profileRootDirectory: profileDirectory, - logger: TestLogger.getTestLogger(), - type: PROFILE_TYPE.BANANA, - typeConfigurations: [bananaProfile] - }); - } catch (e) { - caughtError = e; - TestLogger.error(caughtError.message); - } - - expect(newProfMgr).not.toBeNull(); - expect(caughtError.message).toEqual(""); - }); -}); diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.integration.test.ts b/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.integration.test.ts deleted file mode 100644 index 00c8e6461a..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/BasicProfileManager.integration.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import * as TestUtil from "../../../TestUtil"; -import { ITestEnvironment } from "../../../../__src__/environment/doc/response/ITestEnvironment"; -import { SetupTestEnvironment } from "../../../../__src__/environment/SetupTestEnvironment"; -import { inspect } from "util"; -import { TestLogger } from "../../../../src/TestLogger"; -import { ProfileUtils } from "../../../../../src/profiles"; -import { getConfig, PROFILE_TYPE } from "../src/constants/BasicProfileManagerTestConstants"; - -let TEST_ENVIRONMENT: ITestEnvironment; - -describe("Imperative should allow CLI implementations to read their own profiles and types", function () { - const mainModule = process.mainModule; - const loadChangingDependencies = () => { - return { - Imperative: require("../../../../../src/imperative/src/Imperative").Imperative, - ImperativeConfig: require("../../../../../src/utilities/src/ImperativeConfig").ImperativeConfig, - ImperativeError: require("../../../../../src/error/src/ImperativeError").ImperativeError - }; - }; - - let {Imperative, ImperativeError, ImperativeConfig} = loadChangingDependencies(); - - beforeAll(async () => { - (process.mainModule as any) = { - filename: __filename - }; - - TEST_ENVIRONMENT = await SetupTestEnvironment.createTestEnv({ - cliHomeEnvVar: "CMD_CLI_CLI_HOME", - testName: "basic_profile_mgr" - }); - - // copy existing profiles into test directory - const response = TestUtil.runCliScript(__dirname + "/__scripts__/copy_profiles.sh", TEST_ENVIRONMENT.workingDir); - expect(response.stderr.toString()).toBe(""); - expect(response.status).toBe(0); - }); - - // Initialize imperative before each test - beforeEach(() => { - jest.resetModules(); - ({Imperative, ImperativeError, ImperativeConfig} = loadChangingDependencies()); - }); - - afterAll(() => { - process.mainModule = mainModule; - TestUtil.rimraf(TEST_ENVIRONMENT.workingDir); - }); - - it("should be able to retrieve all defined types after init", async function () { - const config = getConfig(TEST_ENVIRONMENT.workingDir); - await Imperative.init(config); - expect(ProfileUtils.getAllTypeNames(ImperativeConfig.instance.loadedConfig.profiles).length).toEqual(Object.keys(PROFILE_TYPE).length); - expect(ProfileUtils.getAllTypeNames(ImperativeConfig.instance.loadedConfig.profiles)).toContain("banana"); - }); - - it("should receive a failure message when attempting to load a profile that doesn't exist", async function () { - const config = getConfig(TEST_ENVIRONMENT.workingDir); - await Imperative.init(config); - let error; - try { - const response = await Imperative.api.profileManager("banana").load({name: "notreal"}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeInstanceOf(ImperativeError); - }); - - it("should be able to load a specific profile", async function () { - const config = getConfig(TEST_ENVIRONMENT.workingDir); - - await Imperative.init(config); - const loadResponse = await Imperative.api.profileManager("banana").load({name: "legit"}); - TestLogger.info(`Profile loaded success response: ${inspect(loadResponse, {depth: null})}`); - - expect(loadResponse.message).toEqual('Profile "legit" of type "banana" loaded successfully.'); - expect(loadResponse.type).toEqual("banana"); - expect(loadResponse.name).toEqual("legit"); - expect(loadResponse.profile).toBeDefined(); - expect(loadResponse.profile).toEqual({"age": 1000}); - }); - - it("should be able to load a default profile", async function () { - const config = getConfig(TEST_ENVIRONMENT.workingDir); - - await Imperative.init(config); - const loadResponse = await Imperative.api.profileManager("banana").load({loadDefault: true}); - - expect(loadResponse.message).toEqual('Profile "legit" of type "banana" loaded successfully.'); - expect(loadResponse.type).toEqual("banana"); - expect(loadResponse.name).toEqual("legit"); - expect(loadResponse.profile).toBeDefined(); - expect(loadResponse.profile).toEqual({ "age": 1000 }); - }); -}); diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/CliProfileManager.credentials.integration.subtest.ts b/packages/imperative/__tests__/src/packages/profiles/__integration__/CliProfileManager.credentials.integration.subtest.ts deleted file mode 100644 index e4dbc06258..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/CliProfileManager.credentials.integration.subtest.ts +++ /dev/null @@ -1,197 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import * as T from "../../../TestUtil"; -import * as path from "path"; -import * as fs from "fs"; -import { IImperativeConfig } from "../../../../../src/imperative"; -import { keyring } from "@zowe/secrets-for-zowe-sdk"; - -describe("Cli Profile Manager", () => { - const cliBin = path.join(__dirname, "../test_cli/TestCLI.ts"); - const config: IImperativeConfig = require(path.join(__dirname, "../test_cli/TestConfiguration")); - const homeDir: string = config.defaultHome; - const testProfileType = "username-password"; - const username: string = "username"; - const password: number = 0; - const account: string = "account123"; - const secured: string = "secured"; - - beforeAll(async () => { - // ensure the CLI home directory exists before running our copy_profile script - if (!fs.existsSync(homeDir)) { - fs.mkdirSync(homeDir); - } - - // copy existing profiles into test directory - const response = T.runCliScript(path.join(__dirname, "__scripts__/copy_profiles_cli_prof_mgr_creds.sh"), homeDir); - expect(response.stderr.toString()).toBe(""); - expect(response.status).toBe(0); - - // store desired secure properties into the credential vault - await keyring.setPassword("example_with_profiles", "username-password_profile-name_username", - Buffer.from(`"${username}"`).toString("base64") - ); - await keyring.setPassword("example_with_profiles", "username-password_profile-name_password", - Buffer.from(`${password}`).toString("base64") - ); - await keyring.setPassword("example_with_profiles", "username-password_profile-name_account", - Buffer.from(`"${account}"`).toString("base64") - ); - await keyring.setPassword("example_with_profiles", - "username-password_profile-name_myParent_securedProperty_mySecuredChild", - Buffer.from(`"${secured}"`).toString("base64") - ); - }); - - afterAll(async () => { - // delete secure properties from the credential vault - await keyring.deletePassword("example_with_profiles", "username-password_profile-name_username"); - await keyring.deletePassword("example_with_profiles", "username-password_profile-name_password"); - await keyring.deletePassword("example_with_profiles", "username-password_profile-name_account"); - await keyring.deletePassword("example_with_profiles", - "username-password_profile-name_myParent_securedProperty_mySecuredChild" - ); - - // delete the CLI_HOME directory - T.rimraf(homeDir); - }); - - describe("Default Credential Management", () => { - - describe("Generic Success Scenarios", () => { - - it("should load a profile with saved credentials", () => { - const cmd = `display-profile`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - expect(result.stderr).toEqual(""); - expect(JSON.parse(result.stdout)).toEqual({ - myParent: { - insecuredProperty: {myInSecuredChild: "insecured"}, - securedProperty: {mySecuredChild: "secured"} - }, - account, username, password}); - }); - }); - - describe("Generic Failure Scenarios", () => { - const createdName = "profile-name"; - const changedName = "profile-name-changed"; - - const profilePath = path.join(homeDir, "profiles", testProfileType); - const createdPath = path.join(profilePath, createdName + ".yaml"); - const changedPath = path.join(profilePath, changedName + ".yaml"); - - it("should fail if the Credential Manager is unable to find the profile", () => { - // change the name of the profile so that we can break it - fs.renameSync(createdPath, changedPath); - - const cmd = `display-profile`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - - // put the profile back for cleanup - fs.renameSync(changedPath, createdPath); - - expect(result.stderr).toContain( - `Your default profile named ${createdName} does not exist for type ${testProfileType}.` - ); - }); - - it("should fail if the Credential Manager is unable to retrieve a password", () => { - // change the name of the profile so that we can break it - fs.renameSync(createdPath, changedPath); - - const cmd = `display-profile --${testProfileType}-profile ${changedName}`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - - // put the profile back for cleanup - fs.renameSync(changedPath, createdPath); - - expect(T.stripNewLines(result.stderr)).toContain( - `Unable to load the secure field "${username}" associated with ` + - `the profile "${changedName}" of type "${testProfileType}".` - ); - expect(T.stripNewLines(result.stderr)).toContain( - "Could not find an entry in the credential vault for the following:" - ); - expect(T.stripNewLines(result.stderr)).toContain("Service = example_with_profiles"); - expect(T.stripNewLines(result.stderr)).toContain("Account = username-password_profile-name-changed_username"); - }); - }); - - describe("Missing secrets SDK installation", () => { - const secretsSdk = path.join(__dirname, "../../../../../../../node_modules/@zowe/secrets-for-zowe-sdk"); - const renamedSecretsSdk = path.join(__dirname, "../../../../../../../node_modules/@zowe/zowe-for-secrets-sdk"); - - const renameSecretsSdk = () => { - if (fs.existsSync(secretsSdk)) { - fs.renameSync(secretsSdk, renamedSecretsSdk); - } - }; - - // Make sure that the secrets SDK folder is reset to the original name. - afterEach(() => { - if (fs.existsSync(renamedSecretsSdk)) { - fs.renameSync(renamedSecretsSdk, secretsSdk); - } - }); - - it("should fail if secrets SDK is not loaded on using profile handler", () => { - renameSecretsSdk(); - - const cmd = `display-profile`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - - expect(result.stderr).toContain("Command Preparation Failed"); - expect(result.stderr).toContain( - `Unable to load the secure field "${username}" associated with ` + - `the profile "profile-name" of type "${testProfileType}".` - ); - expect(T.stripNewLines(result.stderr)).toContain( - "Failed to load Keytar module: Cannot find module '@zowe/secrets-for-zowe-sdk" - ); - }); - - it("should be able to issue command", () => { - renameSecretsSdk(); - - const cmd = `display-no-secrets`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - expect(result.stderr).toBe(""); - expect(result.stdout).toContain("This handler does not require secrets"); - }); - }); - }); - - describe("Custom Credential Management - Absolute String", () => { - - it("should use an overwritten credential manager - Absolute String", () => { - const cliBin = path.join(__dirname, "../test_cli/TestCustomCredString.ts"); - const cmd = `display-profile`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - expect(result.stderr).toBe(""); - expect(result.stdout).toContain('"username":"custom"'); - expect(result.stdout).toContain('"password":"custom"'); - }); - }); - - describe("Custom Credential Management - Class", () => { - - it("should use an overwritten credential manager - Class", () => { - const cliBin = path.join(__dirname, "../test_cli/TestCustomCredClass.ts"); - const cmd = `display-profile`; - const result = T.executeTestCLICommand(cliBin, this, cmd.split(" ")); - expect(result.stderr).toBe(""); - expect(result.stdout).toContain('"username":"custom"'); - expect(result.stdout).toContain('"password":"custom"'); - }); - }); -}); diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/ProfileCommandExample.integration.test.ts b/packages/imperative/__tests__/src/packages/profiles/__integration__/ProfileCommandExample.integration.test.ts deleted file mode 100644 index 6cbbaf3e75..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/ProfileCommandExample.integration.test.ts +++ /dev/null @@ -1,135 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import * as T from "../../../TestUtil"; -import { IImperativeConfig } from "../../../../../src/imperative"; -import * as yargs from "yargs"; -import { Constants } from "../../../../../src/constants"; -import { CommandProcessor, ICommandDefinition, ICommandProfileTypeConfiguration, ICommandResponse } from "../../../../../src/cmd"; -import { ICommandProcessorParms } from "../../../../../src/cmd/src/doc/processor/ICommandProcessorParms"; -import { isNullOrUndefined } from "util"; -import { TestLogger } from "../../../../src/TestLogger"; -import { AbstractHelpGenerator } from "../../../../../src/cmd/src/help/abstract/AbstractHelpGenerator"; -import { DefaultHelpGenerator } from "../../../../../src/cmd/src/help/DefaultHelpGenerator"; -import { BasicProfileManagerFactory } from "../../../../../src/index"; - -const logger = TestLogger.getTestLogger(); -const PROFILE_CONFIGURATIONS: ICommandProfileTypeConfiguration[] = [{ - type: "banana", - schema: { - type: "object", - title: "The Banana command profile schema", - description: "The Banana command profile schema", - properties: { - age: { - optionDefinition: { - description: "The age of the Banana", - type: "number", - name: "age", aliases: ["a"], - required: true - }, - type: "number", - }, - }, - required: ["age"] - } -}]; -const SAMPLE_CONFIG: IImperativeConfig = { - definitions: [ - { - name: "profile", - type: "command", - options: [], - profile: { - required: ["banana"] - }, - description: "my command", - handler: __dirname + "/handler/SampleHandler" - } - ], - productDisplayName: "My product (packagejson)", - defaultHome: T.TEST_HOME, - rootCommandDescription: "My Product CLI", - profiles: PROFILE_CONFIGURATIONS -}; - -describe("Imperative should allow CLI implementations to configure their own profiles and types", function () { - - /** - * Clean up the home directory before and after each test. - */ - beforeAll(function () { - T.rimraf(T.TEST_HOME); - // return Imperative.init(SAMPLE_CONFIG).then(() => { - // Imperative.api.profileManager("banana").createProfile({name: "legit", age: BANANA_AGE}, - // true, true, - // (error: Error, filePath: string, overwritten: boolean) => { - // expect(error, "Should not get error for valid profile:" + T.inspect(error)).to.not.exist; - // }); - // }); - }); - afterAll(function () { - T.rimraf(T.TEST_HOME); - }); - - function issueCommand(optionString: string, shouldSucceed: boolean, expectedText?: string[]) { - const options: any = yargs.parse(optionString); - // options._ = ["test", "validation-test"].concat(options._); // fake out command structure - options[Constants.JSON_OPTION] = true; - const fakeParent: ICommandDefinition = { - name: undefined, - description: "", type: "group", - children: [SAMPLE_CONFIG.definitions[0]] - }; - const helpGenerator: AbstractHelpGenerator = new DefaultHelpGenerator({ - primaryHighlightColor: "yellow", - produceMarkdown: false, - rootCommandName: "dummy" - }, { - fullCommandTree: fakeParent, - commandDefinition: SAMPLE_CONFIG.definitions[0] - }); - const cmdProcessorParms: ICommandProcessorParms = { - definition: SAMPLE_CONFIG?.definitions?.[0] as ICommandDefinition, - helpGenerator: helpGenerator, - profileManagerFactory: new BasicProfileManagerFactory(T.createUniqueTestDataDir(), PROFILE_CONFIGURATIONS), - rootCommandName: "zoweCmdName", - commandLine: "/path/to/zoweCmdName", - envVariablePrefix: "ZOWE_CLI", - fullDefinition: fakeParent, - promptPhrase: "Any prompt will do:" - }; - return new CommandProcessor(cmdProcessorParms).invoke({arguments: options, responseFormat: "json"}).then( - (completedResponse: ICommandResponse) => { - logger.debug(JSON.stringify(completedResponse)); - if (shouldSucceed) { - // Command should have succeeded - expect(completedResponse.success).toEqual(true); - } else { - // "Command should have failed" - expect(completedResponse.success).toEqual(false); - } - if (!isNullOrUndefined(expectedText) && expectedText.length > 0) { - const fullText = completedResponse.stdout.toString() + - completedResponse.stderr.toString(); - for (const text of expectedText) { - expect(fullText).toContain(text); - } - } - // done(); - }); - } - - // eslint-disable-next-line jest/expect-expect, jest/no-disabled-tests - it.skip("We should be able to issue a command and have a profile be automatically loaded", function () { - // return issueCommand.bind(this, ["profile"], true)(); - }); -}); diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/banana_meta.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/banana_meta.yaml deleted file mode 100644 index e7cbb9cc9c..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/banana_meta.yaml +++ /dev/null @@ -1,19 +0,0 @@ -defaultProfile: legit -configuration: - type: banana - schema: - type: object - title: 'The Banana command profile schema' - description: 'The Banana command profile schema' - properties: - age: - optionDefinition: - description: 'The age of the Banana' - type: number - name: age - aliases: - - a - required: true - type: number - required: - - age diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/legit.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/legit.yaml deleted file mode 100644 index e98b69963c..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/banana/legit.yaml +++ /dev/null @@ -1 +0,0 @@ -age: 1000 diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/secure_orange/secure_orange_meta.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/secure_orange/secure_orange_meta.yaml deleted file mode 100644 index 97720a614c..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/secure_orange/secure_orange_meta.yaml +++ /dev/null @@ -1,21 +0,0 @@ -defaultProfile: null -configuration: - type: secure_orange - schema: - type: object - title: 'The secure_orange command profile schema' - description: 'The secure_orange command profile schema' - properties: - username: - optionDefinition: - description: 'The username of the secure_orange' - type: string - name: username - type: string - password: - optionDefinition: - description: 'The password of the secure_orange' - type: string - name: password - type: string - required: [] diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/strawberry/strawberry_meta.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/strawberry/strawberry_meta.yaml deleted file mode 100644 index 28f1719583..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles/strawberry/strawberry_meta.yaml +++ /dev/null @@ -1,19 +0,0 @@ -defaultProfile: null -configuration: - type: strawberry - schema: - type: object - title: 'The strawberry command profile schema' - description: 'The strawberry command profile schema' - properties: - age: - optionDefinition: - description: 'The age of the strawberry' - type: number - name: age - aliases: - - a - required: true - type: number - required: - - age diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/profile-name.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/profile-name.yaml deleted file mode 100644 index 45141c58b1..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/profile-name.yaml +++ /dev/null @@ -1,8 +0,0 @@ -username: 'managed by Test CLI with Profiles' -password: 'managed by Test CLI with Profiles' -account: 'managed by Test CLI with Profiles' -myParent: - securedProperty: - mySecuredChild: 'managed by Test CLI with Profiles' - insecuredProperty: - myInSecuredChild: insecured diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/username-password_meta.yaml b/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/username-password_meta.yaml deleted file mode 100644 index e3a32193d8..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__resources__/profiles_cli_prof_mgr_creds/username-password/username-password_meta.yaml +++ /dev/null @@ -1,57 +0,0 @@ -defaultProfile: profile-name -configuration: - type: username-password - schema: - type: object - title: 'Profile Manager Test Profile' - description: 'user name and password test profile' - properties: - username: - optionDefinition: - description: 'User Name' - type: string - name: username - required: true - secure: true - type: string - password: - optionDefinition: - description: Password - type: number - name: password - required: true - secure: true - type: number - account: - optionDefinition: - description: Account - type: string - name: account - required: true - secure: true - type: string - myParent: - type: object - properties: - securedProperty: - type: object - properties: - mySecuredChild: - optionDefinition: - description: 'The secured property' - type: string - name: sec1 - required: true - secure: true - type: string - insecuredProperty: - type: object - properties: - myInSecuredChild: - optionDefinition: - description: 'The insecured property' - type: string - name: insec1 - required: true - secure: false - type: string diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles.sh b/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles.sh deleted file mode 100644 index 74a8cfcbca..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# copy pre-existing profiles to test directory -cp -r $myScriptDir/../__resources__/profiles profiles -exitOnFailure "Failed to copy test profile." $? diff --git a/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles_cli_prof_mgr_creds.sh b/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles_cli_prof_mgr_creds.sh deleted file mode 100644 index d44b849331..0000000000 --- a/packages/imperative/__tests__/src/packages/profiles/__integration__/__scripts__/copy_profiles_cli_prof_mgr_creds.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# include zowe-cli\__tests__\__scripts__\exitOnFailure function -myScriptDir=`dirname $0` -. $myScriptDir/../../../../../../../../__tests__/__scripts__/exitOnFailure.sh - -# copy pre-existing profiles to test directory -cp -r $myScriptDir/../__resources__/profiles_cli_prof_mgr_creds ./profiles -exitOnFailure "Failed to copy test profiles." $? diff --git a/packages/imperative/__tests__/src/packages/profiles/src/handler/SampleHandler.ts b/packages/imperative/__tests__/src/packages/profiles/src/handler/SampleHandler.ts index b7972b09be..c8495c454d 100644 --- a/packages/imperative/__tests__/src/packages/profiles/src/handler/SampleHandler.ts +++ b/packages/imperative/__tests__/src/packages/profiles/src/handler/SampleHandler.ts @@ -10,12 +10,14 @@ */ import { ICommandHandler, IHandlerParameters } from "../../../../../../src/cmd"; +import { ImperativeConfig } from "../../../../../../src/utilities"; import { isNullOrUndefined } from "util"; import { ImperativeError } from "../../../../../../src/error"; export default class SampleHandler implements ICommandHandler { public async process(commandParameters: IHandlerParameters) { - const profile: any = commandParameters.profiles.get("banana"); + const profile: any = ImperativeConfig.instance.config.api.profiles.get("banana"); + if (isNullOrUndefined(profile)) { const errMsg = commandParameters.response.console.error("Failed to load a profile of type banana"); throw new ImperativeError({msg: errMsg}); diff --git a/packages/imperative/src/cmd/__tests__/CommandProcessor.unit.test.ts b/packages/imperative/src/cmd/__tests__/CommandProcessor.unit.test.ts index b5b3e44b10..aaaa738106 100644 --- a/packages/imperative/src/cmd/__tests__/CommandProcessor.unit.test.ts +++ b/packages/imperative/src/cmd/__tests__/CommandProcessor.unit.test.ts @@ -15,7 +15,6 @@ import { CommandProcessor } from "../src/CommandProcessor"; import { ICommandResponse } from "../src/doc/response/response/ICommandResponse"; import { CommandResponse } from "../src/response/CommandResponse"; import { IHelpGenerator } from "../src/help/doc/IHelpGenerator"; -import { BasicProfileManager, IProfileManagerFactory, IProfileTypeConfiguration } from "../../profiles"; import { ImperativeError } from "../../error"; import { ICommandValidatorResponse } from "../src/doc/response/response/ICommandValidatorResponse"; import { SharedOptions } from "../src/utils/SharedOptions"; @@ -182,59 +181,6 @@ const SAMPLE_COMMAND_REAL_HANDLER_WITH_DEFAULT_OPT: ICommandDefinition = { } }; -// A fake instance of the profile manager factory -const FAKE_PROFILE_MANAGER_FACTORY: IProfileManagerFactory = { - getManager: () => { - return new BasicProfileManager({ - profileRootDirectory: "FAKE_ROOT", - type: "banana", - typeConfigurations: [ - { - type: "banana", - schema: { - title: "fake banana schema", - type: "object", - description: "", - properties: {} - } - } - ] - }); - } -}; - -// A fake instance of the profile manager factory with props -const FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS: IProfileManagerFactory = { - getManager: () => { - return new BasicProfileManager({ - profileRootDirectory: "FAKE_ROOT", - type: "banana", - typeConfigurations: [ - { - type: "banana", - schema: { - title: "fake banana schema", - type: "object", - description: "", - properties: { - color: { - type: "string", - optionDefinition: { - name: "color", - aliases: ["c"], - description: "The color of the banana.", - type: "string", - required: true, - }, - } - } - } - } - ] - }); - } -}; - // A fake instance of the help generator const FAKE_HELP_GENERATOR: IHelpGenerator = { buildHelp: function buildHelp(): string { @@ -260,7 +206,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -291,7 +236,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: undefined, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -311,27 +255,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: undefined, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, - rootCommandName: SAMPLE_ROOT_COMMAND, - commandLine: "", - promptPhrase: "dummydummy" - }); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect no profile manager factory supplied", () => { - let error; - try { - const processor: CommandProcessor = new CommandProcessor({ - envVariablePrefix: ENV_VAR_PREFIX, - definition: SAMPLE_COMMAND_DEFINITION, - helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: undefined, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -351,7 +274,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: undefined, commandLine: "", promptPhrase: "dummydummy" @@ -371,7 +293,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: "", commandLine: "", promptPhrase: "dummydummy" @@ -391,7 +312,6 @@ describe("Command Processor", () => { envVariablePrefix: undefined, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -409,7 +329,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -422,7 +341,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -435,7 +353,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -448,7 +365,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -461,7 +377,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -474,12 +389,14 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" }); - expect(processor.profileFactory).toEqual(FAKE_PROFILE_MANAGER_FACTORY); + expect(processor instanceof CommandProcessor).toBe(true); + expect(processor.envVariablePrefix).toEqual(ENV_VAR_PREFIX); + expect(processor.definition).toEqual(SAMPLE_COMMAND_DEFINITION); + expect(processor.promptPhrase).toEqual("dummydummy"); }); it("should build the help if requested", () => { @@ -491,7 +408,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -516,7 +432,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -542,7 +457,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -568,7 +482,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -590,7 +503,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -610,7 +522,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -633,7 +544,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -660,7 +570,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -683,7 +592,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -706,7 +614,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -730,7 +637,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -754,7 +660,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -778,7 +683,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -805,7 +709,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -833,7 +736,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -858,7 +760,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "--user fakeUser --password fakePass --token-value fakeToken " + "--cert-file-passphrase fakePassphrase --cert-key-file /fake/path", @@ -893,7 +794,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -931,7 +831,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -986,7 +885,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: commandDef, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1038,7 +936,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: commandDef, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1099,7 +996,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: commandDef, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1142,7 +1038,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1193,7 +1088,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1244,7 +1138,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1295,7 +1188,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1349,7 +1241,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1398,7 +1289,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1440,7 +1330,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1497,7 +1386,6 @@ describe("Command Processor", () => { ], }, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1517,34 +1405,81 @@ describe("Command Processor", () => { expect(commandResponse.data.commandValues[parm1Key]).toBe(parm1Value); }); - it("should display input value for simple parm when --show-inputs-only flag is set and v1 profile exists", async () => { + it("should display input value for simple parm when --show-inputs-only flag is set and team config exists", async () => { // values to test const parm1Key = `parm1`; const parm1Value = `value1`; + await setupConfigToLoad({ + "profiles": { + "fruit": { + "properties": { + "origin": "California" + }, + "profiles": { + "apple": { + "type": "fruit", + "properties": { + "color": "red" + } + }, + "banana": { + "type": "fruit", + "properties": { + "color": "yellow" + } + }, + "orange": { + "type": "fruit", + "properties": { + "color": "orange" + } + } + }, + "secure": [] + } + }, + "defaults": { + "fruit": "fruit.apple", + "banana": "fruit.banana" + }, + "plugins": [ + "@zowe/fruit-for-imperative" + ] + }); + // Allocate the command processor const processor: CommandProcessor = new CommandProcessor({ envVariablePrefix: ENV_VAR_PREFIX, fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, // `group action` - definition: { // `object` + definition: { name: "banana", description: "The banana command", type: "command", - handler: __dirname + "/__model__/TestCmdHandler", + handler: __dirname + "/__model__/TestArgHandler", options: [ { - name: parm1Key, + name: "boolean-opt", + type: "boolean", + description: "A boolean option.", + }, + { + name: "color", type: "string", - description: "The first parameter", + description: "The banana color.", + required: true } ], + profile: { + optional: ["banana"] + } }, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", - promptPhrase: "dummydummy" + promptPhrase: "dummydummy", + config: ImperativeConfig.instance.config }); // Mock the profile loader @@ -1556,13 +1491,6 @@ describe("Command Processor", () => { }; }); - // return the "fake" args object with values from profile - CliUtils.getOptValueFromProfiles = jest.fn((cmdProfiles, profileDef, allOpts) => { - return { - color: "yellow" - }; - }); - const parms: any = { arguments: { _: ["check", "for", "banana"], @@ -1574,15 +1502,16 @@ describe("Command Processor", () => { silent: true }; const commandResponse: ICommandResponse = await processor.invoke(parms); - expect(commandResponse.data.locations[0]).toContain('home'); - expect(commandResponse.data.profileVersion).toBe('v1'); + expect(commandResponse.data.locations.length).toBeGreaterThan(0); + expect(commandResponse.data.optionalProfiles[0]).toBe(`banana`); + expect(commandResponse.data.requiredProfiles).toBeUndefined(); }); - - it("should display input value for simple parm when --show-inputs-only flag is set and v2 config exists", async () => { + it("should mask input value for a secure parm when --show-inputs-only flag is set", async () => { // values to test - const parm1Key = `parm1`; - const parm1Value = `value1`; + const secretParmKey = `brownSpots`; + const secretParmValue = true; + const secure = `(secure value)`; await setupConfigToLoad({ "profiles": { @@ -1600,8 +1529,12 @@ describe("Command Processor", () => { "banana": { "type": "fruit", "properties": { - "color": "yellow" - } + "color": "yellow", + secretParmKey : secretParmValue + }, + "secure": [ + secretParmKey + ] }, "orange": { "type": "fruit", @@ -1609,8 +1542,7 @@ describe("Command Processor", () => { "color": "orange" } } - }, - "secure": [] + } } }, "defaults": { @@ -1642,14 +1574,18 @@ describe("Command Processor", () => { type: "string", description: "The banana color.", required: true - } + }, + { + name: secretParmKey, + type: "boolean", + description: "Whether or not the banana has brown spots" + }, ], profile: { optional: ["banana"] } }, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy", @@ -1669,64 +1605,18 @@ describe("Command Processor", () => { arguments: { _: ["check", "for", "banana"], $0: "", - [parm1Key]: parm1Value, + [secretParmKey]: secretParmValue, valid: true, showInputsOnly: true, }, silent: true }; + const commandResponse: ICommandResponse = await processor.invoke(parms); expect(commandResponse.data.locations.length).toBeGreaterThan(0); expect(commandResponse.data.optionalProfiles[0]).toBe(`banana`); + expect(commandResponse.data.commandValues[secretParmKey]).toBe(secure); expect(commandResponse.data.requiredProfiles).toBeUndefined(); - expect(commandResponse.data.profileVersion).toBe('v2'); - }); - - - it("should mask input value for a secure parm when --show-inputs-only flag is set", async () => { - - // values to test - const parm1Key = `user`; - const parm1Value = `secret`; - const secure = `(secure value)`; - - // Allocate the command processor - const processor: CommandProcessor = new CommandProcessor({ - envVariablePrefix: ENV_VAR_PREFIX, - fullDefinition: SAMPLE_COMPLEX_COMMAND, // `group action` - definition: { // `object` - name: "banana", - description: "The banana command", - type: "command", - handler: __dirname + "/__model__/TestCmdHandler", - options: [ - { - name: parm1Key, - type: "string", - description: "The first parameter", - } - ], - }, - helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, - rootCommandName: SAMPLE_ROOT_COMMAND, - commandLine: "", - promptPhrase: "dummydummy" - }); - - const parms: any = { - arguments: { - _: ["check", "for", "banana"], - $0: "", - [parm1Key]: parm1Value, - valid: true, - showInputsOnly: true, - }, - silent: true - }; - const commandResponse: ICommandResponse = await processor.invoke(parms); - expect(commandResponse.data.commandValues[parm1Key]).toBe(secure); - expect(commandResponse.stderr.toString()).toContain(`Some inputs are not displayed`); }); it("should not mask input value for a secure parm when --show-inputs-only flag is set with env setting", async () => { @@ -1755,7 +1645,6 @@ describe("Command Processor", () => { ], }, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1785,7 +1674,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy", @@ -1852,7 +1740,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy", @@ -1920,7 +1807,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -1969,7 +1855,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_DEFAULT_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2015,7 +1900,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_POS_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2064,7 +1948,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_POS_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2114,7 +1997,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_CMD_WITH_OPTS_AND_PROF, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY_WITH_PROPS, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2165,7 +2047,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMPLEX_COMMAND, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2183,7 +2064,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_WIH_NO_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2204,7 +2084,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2249,7 +2128,6 @@ describe("Command Processor", () => { fullDefinition: SAMPLE_COMPLEX_COMMAND, definition: SAMPLE_COMMAND_REAL_HANDLER, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2332,7 +2210,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2359,7 +2236,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2386,7 +2262,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_DEFINITION_WITH_EXAMPLES, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy" @@ -2459,7 +2334,6 @@ describe("Command Processor", () => { envVariablePrefix: ENV_VAR_PREFIX, definition: SAMPLE_COMMAND_REAL_HANDLER_WITH_OPT, helpGenerator: FAKE_HELP_GENERATOR, - profileManagerFactory: FAKE_PROFILE_MANAGER_FACTORY, rootCommandName: SAMPLE_ROOT_COMMAND, commandLine: "", promptPhrase: "dummydummy", diff --git a/packages/imperative/src/cmd/__tests__/__snapshots__/CommandProcessor.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/__snapshots__/CommandProcessor.unit.test.ts.snap index eec473605e..0ba333dff1 100644 --- a/packages/imperative/src/cmd/__tests__/__snapshots__/CommandProcessor.unit.test.ts.snap +++ b/packages/imperative/src/cmd/__tests__/__snapshots__/CommandProcessor.unit.test.ts.snap @@ -131,8 +131,6 @@ exports[`Command Processor should detect no command definition supplied 1`] = `" exports[`Command Processor should detect no help generator supplied 1`] = `"Expect Error: Command Processor Error: No help generator supplied."`; -exports[`Command Processor should detect no profile manager factory supplied 1`] = `"Expect Error: Command Processor Error: No profile manager factory supplied."`; - exports[`Command Processor should detect no root command supplied 1`] = `"Expect Error: Command Processor Error: No root command supplied."`; exports[`Command Processor should detect that no parameters have been supplied 1`] = `"Expect Error: Command Processor Error: No parameters supplied to constructor."`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.credentials.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.credentials.unit.test.ts deleted file mode 100644 index 0e57e741ce..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.credentials.unit.test.ts +++ /dev/null @@ -1,633 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { TestLogger } from "../../../../__tests__/src/TestLogger"; -import { ProfileIO } from "../../../profiles/src/utils/ProfileIO"; -import { CliProfileManager } from "../../src/profiles/CliProfileManager"; -import { IProfile } from "../../../profiles/src/doc/definition/IProfile"; -import { - ONLY_ORANGE_WITH_CREDENTIALS, - SECURE_ORANGE_PROFILE_TYPE, - TEST_PROFILE_ROOT_DIR -} from "../../../profiles/__tests__/TestConstants"; -import { CredentialManagerFactory, DefaultCredentialManager } from "../../../security"; -import { BasicProfileManager } from "../../../profiles/src/BasicProfileManager"; -import { ProfilesConstants, ISaveProfile, IProfileSaved } from "../../../profiles"; - -jest.mock("../../../profiles/src/utils/ProfileIO"); -jest.mock("../../../security/src/DefaultCredentialManager"); - -// TODO: Some of these tests are not completely isolated, some may cause others to fail depending on mocks - -// **NOTE:** DefaultCredentialManager is mocked in such a way that the constructor parameters don't matter here. -// **NOTE:** Check the mocked file for what is actually used. - -describe("Cli Profile Manager", () => { - let writtenProfile: any; - - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - - afterEach(() => { - writtenProfile = undefined; // clear any saved profile to not pollute results across tests - }); - - describe("Credential Manager functionality", () => { - let prof: CliProfileManager; - let parms: any; - const securelyStored = ProfilesConstants.PROFILES_OPTION_SECURELY_STORED + " dummy manager"; - const credentialManagerErrorMessage = /(Unable to).*(the secure field)/; - - const user = "username"; - const pass = "password"; - const phone = "{\"a\":\"b\"}"; - const code = 0; - const phrase = "phrase"; - const set = ["a1,a2", "b2"]; - const flag = false; - const minime = "mini-me"; - const name = "My-secure-orange"; - const description = "A secure orange"; - - beforeEach(() => { - prof = new CliProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_ORANGE_WITH_CREDENTIALS, - type: SECURE_ORANGE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - // We need to define parms every time since implementation explicitly deletes the username and password properties from memory - parms = { - name, - profile: { - description: "A secure orange" - }, - overwrite: false, - args: { - user, - phone, - code, - phrase, - set, - flag, - minime - } - }; - - prof.setDefault = jest.fn(); - }); - - describe("Save operation", () => { - it("should save credentials and store a profile with a constant string value for secure properties", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.save = jest.fn(); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - const tempProf: any = { - username: user, - password: undefined, - secureBox: { - myCode: securelyStored, - myFlag: securelyStored, - myMiniBox: securelyStored, - myPhone: securelyStored, - myPhrase: securelyStored, - mySet: securelyStored, - myEmptyMiniBox: null, - } - }; - - jest.spyOn(BasicProfileManager.prototype, "saveProfile" as any).mockImplementation((tParms: ISaveProfile | any) => { - return { - overwritten: tParms.overwrite, - profile: tParms.profile - }; - }); - - const result = await prof.save(parms); - - // Parms should be successfully deleted form memory - expect(parms.args).toBeUndefined(); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).saveProfile).toHaveBeenCalledWith({ - name, - type: "secure-orange", - overwrite: false, - profile: tempProf - }); - - // Should have saved every secure property as a constant string - expect(result.profile).toMatchObject(tempProf); - - // writtenProfile === undefined since BasicProfileManager gets mocked and doesn't call ProfileIO.writeProfile - expect(writtenProfile).toBeUndefined(); - - (BasicProfileManager.prototype as any).saveProfile.mockRestore(); - }); - - it("should not invoke the credential manager if it has not been initialized", async () => { - // We'll use a dummy credential manager in the test - but set initialized to "false" - this way we can use - // Jest expect.toHaveBeenCalledTimes(0) - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.save = jest.fn(); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(false)}); - - const tempProf: any = { - username: user, - password: null, - secureBox: { - myCode: securelyStored, - myFlag: securelyStored, - myMiniBox: securelyStored, - myPhone: securelyStored, - myPhrase: securelyStored, - mySet: securelyStored, - myEmptyMiniBox: null, - } - }; - - jest.spyOn(BasicProfileManager.prototype, "saveProfile" as any).mockImplementation((tParms: ISaveProfile | any) => { - return { - overwritten: tParms.overwrite, - profile: tParms.profile - }; - }); - - await prof.save(parms); - - // Parms should be successfully deleted form memory - expect(parms.args).toBeUndefined(); - - // writtenProfile === undefined since BasicProfileManager gets mocked and doesn't call ProfileIO.writeProfile - expect(writtenProfile).toBeUndefined(); - - // Expect the credential manager save to have NOT been called - expect(dummyManager.save).toHaveBeenCalledTimes(0); - - (BasicProfileManager.prototype as any).saveProfile.mockRestore(); - }); - - it("should save credentials without erroring the credential manager if there are no secure credentials to save", async () => { - // We'll use a dummy credential manager in the test - but set initialized to "false" - this way we can use - // Jest expect.toHaveBeenCalledTimes(0) - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.save = jest.fn(); - dummyManager.delete = jest.fn(() => { - throw new Error("This is a dummy error that is thrown"); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - const tempProf: any = { - username: user, - password: undefined, - secureBox: { - myCode: undefined, - myFlag: undefined, - myMiniBox: null, - myPhone: undefined, - myPhrase: undefined, - mySet: undefined, - myEmptyMiniBox: null, - } - }; - - parms.args.phone = undefined; - parms.args.code = undefined; - parms.args.phrase = undefined; - parms.args.set = undefined; - parms.args.flag = undefined; - parms.args.minime = undefined; - - jest.spyOn(BasicProfileManager.prototype, "saveProfile" as any).mockImplementation((tParms: ISaveProfile | any) => { - return { - overwritten: tParms.overwrite, - profile: tParms.profile - }; - }); - - let result: IProfileSaved; - let errorMessage: string; - try { - result = await prof.save(parms); - } catch (err) { - errorMessage = err.message; - } - // Parms should be successfully deleted from memory - expect(parms.args).toBeUndefined(); - expect(errorMessage).toBeUndefined(); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).saveProfile).toHaveBeenCalledWith({ - name, - type: "secure-orange", - overwrite: false, - profile: tempProf - }); - - // Should have saved every secure property as a constant string - expect(result.profile).toMatchObject(tempProf); - - // Expect the credential manager save to not have been called - // and delete to have been called a few (6) times, but still work - // even if it threw an error. - expect(dummyManager.save).toHaveBeenCalledTimes(0); - expect(dummyManager.delete).toHaveBeenCalledTimes(6); - - (BasicProfileManager.prototype as any).saveProfile.mockRestore(); - }); - - it("should fail if the Credential Manager throws an error", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.save = jest.fn(() => { - throw new Error("dummy error"); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - - let errorMessage = ""; - try { - await prof.save(parms); - } catch (err) { - errorMessage = err.message; - } - - expect(errorMessage).toMatch(credentialManagerErrorMessage); - }); - }); - - describe("Update operation", () => { - const tempProf: any = { - description, - username: user, - password: undefined, - secureBox: { - myCode: securelyStored, - myFlag: securelyStored, - myMiniBox: securelyStored, - myPhone: securelyStored, - myPhrase: securelyStored, - mySet: securelyStored, - myEmptyMiniBox: null, - } - }; - - it("should update credentials and store a profile with a constant string value for secure properties", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - const mockDeleteCreds = jest.fn(); - dummyManager.delete = mockDeleteCreds; - dummyManager.save = jest.fn(); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - - jest.spyOn(BasicProfileManager.prototype, "saveProfile" as any).mockImplementation((tParms: ISaveProfile | any) => { - return { - overwritten: tParms.overwrite, - profile: tParms.profile - }; - }); - - jest.spyOn(CliProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: tempProf - }); - - const result = await prof.update(parms); - - // Parms should be successfully deleted form memory - expect(parms.args).toBeUndefined(); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).saveProfile).toHaveBeenCalledWith({ - name, - type: "secure-orange", - overwrite: true, - profile: tempProf, - updateDefault: false - }); - - // Should have updated every secure property as a constant string - expect(result.profile).toMatchObject(tempProf); - - // writtenProfile === undefined since BasicProfileManager gets mocked and doesn't call ProfileIO.writeProfile - expect(writtenProfile).toBeUndefined(); - - // Should have deleted credentials for password in case it was defined previously - expect(mockDeleteCreds).toHaveBeenCalledTimes(1); - expect(mockDeleteCreds.mock.calls[0][0]).toContain("password"); - - (CliProfileManager.prototype as any).loadProfile.mockRestore(); - (BasicProfileManager.prototype as any).saveProfile.mockRestore(); - }); - - it("should fail if the Credential Manager throws an error", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.save = jest.fn(() => { - throw new Error("dummy error"); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - - jest.spyOn(CliProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: tempProf - }); - - let errorMessage = ""; - try { - await prof.update(parms); - } catch (err) { - errorMessage = err.message; - } - - expect(errorMessage).toMatch(credentialManagerErrorMessage); - - (CliProfileManager.prototype as any).loadProfile.mockRestore(); - }); - }); - - describe("Load operation", () => { - const tempProf: any = { - name, - username: user, - password: null, - type: SECURE_ORANGE_PROFILE_TYPE, - secureBox: { - myCode: securelyStored, - myFlag: securelyStored, - myMiniBox: securelyStored, - myPhone: securelyStored, - myPhrase: securelyStored, - mySet: securelyStored, - myEmptyMiniBox: null, - } - }; - - it("should load credentials from a profile with constant string values for secure properties", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.load = jest.fn(async (propKey: string) => { - let ret: any = null; - if (propKey.indexOf("myCode") >= 0) { - ret = code; - } else if (propKey.indexOf("myFlag") >= 0) { - ret = flag; - } else if (propKey.indexOf("myMiniBox") >= 0) { - ret = {minime}; - } else if (propKey.indexOf("myPhone") >= 0) { - ret = phone; - } else if (propKey.indexOf("myPhrase") >= 0) { - ret = phrase; - } else if (propKey.indexOf("mySet") >= 0) { - ret = set; - } - return JSON.stringify(ret); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - - // same object but with real values - const copyTempProf = JSON.parse(JSON.stringify(tempProf)); - copyTempProf.secureBox = { - myCode: code, - myFlag: flag, - myMiniBox: {minime}, - myPhone: phone, - myPhrase: phrase, - mySet: set, - myEmptyMiniBox: null, - }; - - jest.spyOn(BasicProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: tempProf // This profile will be altered by reference with the real values by CliProfileManager.loadProfile - }); - - const result = await prof.load({name}); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).loadProfile).toHaveBeenCalledWith( - {name, failNotFound: true, loadDefault: false, loadDependencies: true} - ); - - // Compare to the modified-by-reference profile - expect(result.profile).toMatchObject(tempProf); - - // Compare to our manually modified profile - expect(result.profile).toMatchObject(copyTempProf); - - (BasicProfileManager.prototype as any).loadProfile.mockRestore(); - }); - - it("should not load credentials from a profile if noSecure is specified", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.load = jest.fn(async (propKey: string) => { - let ret: any = null; - if (propKey.indexOf("myCode") >= 0) { - ret = code; - } else if (propKey.indexOf("myFlag") >= 0) { - ret = flag; - } else if (propKey.indexOf("myMiniBox") >= 0) { - ret = {minime}; - } else if (propKey.indexOf("myPhone") >= 0) { - ret = phone; - } else if (propKey.indexOf("myPhrase") >= 0) { - ret = phrase; - } else if (propKey.indexOf("mySet") >= 0) { - ret = set; - } - return JSON.stringify(ret); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - // same object but with real values - const copyTempProf = JSON.parse(JSON.stringify(tempProf)); - copyTempProf.secureBox = { - myCode: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myFlag: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myMiniBox: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myPhone: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myPhrase: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - mySet: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myEmptyMiniBox: null, - }; - - jest.spyOn(BasicProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: copyTempProf - }); - - const result = await prof.load({name, noSecure: true}); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).loadProfile).toHaveBeenCalledWith( - {name, failNotFound: true, loadDefault: false, loadDependencies: true, noSecure: true} - ); - - // Compare to the modified-by-reference profile - expect(result.profile).toMatchSnapshot(); - - (BasicProfileManager.prototype as any).loadProfile.mockRestore(); - }); - - it("should not attempt to load secure fields if no credential manager is present", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.load = jest.fn(async (propKey: string) => { - let ret: any = null; - if (propKey.indexOf("myCode") >= 0) { - ret = code; - } else if (propKey.indexOf("myFlag") >= 0) { - ret = flag; - } else if (propKey.indexOf("myMiniBox") >= 0) { - ret = {minime}; - } else if (propKey.indexOf("myPhone") >= 0) { - ret = phone; - } else if (propKey.indexOf("myPhrase") >= 0) { - ret = phrase; - } else if (propKey.indexOf("mySet") >= 0) { - ret = set; - } - return JSON.stringify(ret); - }); - - // Even, though it should not get the manager, we'll add a dummy to test if it gets called - const notCalledManager = jest.fn().mockReturnValue(dummyManager); - Object.defineProperty(CredentialManagerFactory, "manager", {get: notCalledManager}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(false)}); - - // same object but with real values - const copyTempProf = JSON.parse(JSON.stringify(tempProf)); - copyTempProf.secureBox = { - myCode: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myFlag: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myMiniBox: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myPhone: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myPhrase: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - mySet: ProfilesConstants.PROFILES_OPTION_SECURELY_STORED, - myEmptyMiniBox: null, - }; - - jest.spyOn(BasicProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: copyTempProf - }); - - const result = await prof.load({name}); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).loadProfile).toHaveBeenCalledWith( - {name, failNotFound: true, loadDefault: false, loadDependencies: true} - ); - - // Compare to the modified-by-reference profile - expect(result.profile).toMatchSnapshot(); - - // The dummy manager should not have been called - expect(notCalledManager).toHaveBeenCalledTimes(0); - - (BasicProfileManager.prototype as any).loadProfile.mockRestore(); - }); - - it("should fail if the Credential Manager throws an error", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.load = jest.fn(() => { - throw new Error("dummy error"); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - jest.spyOn(BasicProfileManager.prototype, "loadProfile" as any).mockReturnValue({ - profile: tempProf - }); - - let errorMessage = ""; - try { - await prof.load({name}); - } catch (err) { - errorMessage = err.message; - } - - expect(errorMessage).toMatch(credentialManagerErrorMessage); - - (BasicProfileManager.prototype as any).loadProfile.mockRestore(); - }); - }); - - describe("Delete operation", () => { - it("should delete credentials and profile with with secure properties", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.delete = jest.fn(); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - jest.spyOn(ProfileIO, "exists").mockReturnValue(true as any); - - jest.spyOn(BasicProfileManager.prototype, "deleteProfileFromDisk" as any).mockImplementation(() => "dummy-path"); - - const result = await prof.delete({name}); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).deleteProfileFromDisk).toHaveBeenCalledWith(name); - - // Should have saved every secure property as a constant string - expect(result.message).toMatch(/(Profile).*(delete).*(success).*/); - - (BasicProfileManager.prototype as any).deleteProfileFromDisk.mockRestore(); - (ProfileIO as any).exists.mockRestore(); - }); - - it("should not invoke the credential manager if it has not been initialized", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.delete = jest.fn(); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(false)}); - - jest.spyOn(ProfileIO, "exists").mockReturnValue(true as any); - - jest.spyOn(BasicProfileManager.prototype, "deleteProfileFromDisk" as any).mockImplementation(() => "dummy-path"); - - const result = await prof.delete({name}); - - // BasicProfileManager should be called to save the profile with the given options - expect((BasicProfileManager.prototype as any).deleteProfileFromDisk).toHaveBeenCalledWith(name); - - // Should have saved every secure property as a constant string - expect(result.message).toMatch(/(Profile).*(delete).*(success).*/); - - // Should not have called the credential manager delete - expect(dummyManager.delete).toHaveBeenCalledTimes(0); - - (BasicProfileManager.prototype as any).deleteProfileFromDisk.mockRestore(); - (ProfileIO as any).exists.mockRestore(); - }); - - it("should fail if the Credential Manager throws an error", async () => { - const dummyManager = new DefaultCredentialManager("dummy"); - dummyManager.delete = jest.fn(() => { - throw new Error("dummy error"); - }); - Object.defineProperty(CredentialManagerFactory, "manager", {get: jest.fn().mockReturnValue(dummyManager)}); - Object.defineProperty(CredentialManagerFactory, "initialized", {get: jest.fn().mockReturnValue(true)}); - - jest.spyOn(ProfileIO, "exists").mockReturnValue(true as any); - - let errorMessage = ""; - try { - await prof.delete({name}); - } catch (err) { - errorMessage = err.message; - } - - expect(errorMessage).toMatch(credentialManagerErrorMessage); - - (ProfileIO as any).exists.mockRestore(); - }); - }); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.unit.test.ts index f221f0dc64..8985e6b2a0 100644 --- a/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.unit.test.ts +++ b/packages/imperative/src/cmd/__tests__/profiles/CliProfileManager.unit.test.ts @@ -9,816 +9,172 @@ * */ -import { ProfileUtils } from "../../../profiles/src/utils/ProfileUtils"; +import { ImperativeError } from "../../../error"; import { TestLogger } from "../../../../__tests__/src/TestLogger"; -import { ICommandProfileTypeConfiguration } from "../../src/doc/profiles/definition/ICommandProfileTypeConfiguration"; -import { ProfileIO } from "../../../profiles/src/utils/ProfileIO"; +import { APPLE_PROFILE_TYPE, ONLY_APPLE } from "./TestConstants"; import { CliProfileManager } from "../../src/profiles/CliProfileManager"; -import { IProfile } from "../../../profiles/src/doc/definition/IProfile"; -import { inspect } from "util"; -import { ISaveProfileFromCliArgs } from "../../../profiles/src/doc/parms/ISaveProfileFromCliArgs"; -import { ImperativeError } from "../../../error/src/ImperativeError"; -import { PROFILE_TYPE } from "../../../../__tests__/src/packages/profiles/src/constants/BasicProfileManagerTestConstants"; -import { TEST_PROFILE_ROOT_DIR } from "../../../profiles/__tests__/TestConstants"; -import { IProfileLoaded } from "../../.."; +import { IProfileTypeConfiguration } from "../../../profiles/src/doc/config/IProfileTypeConfiguration"; -jest.mock("../../../profiles/src/utils/ProfileIO"); -jest.mock("../../../security/src/DefaultCredentialManager"); - -describe("Cli Profile Manager", () => { - let writtenProfile: any; - - const originalSaveProfile = (CliProfileManager.prototype as any).saveProfile; - afterEach(() => { - (CliProfileManager.prototype as any).saveProfile = originalSaveProfile; - }); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - - ProfileIO.exists = jest.fn((path: string) => { - return path.indexOf("meta") === -1 ? path : undefined; - }); - - (ProfileIO.readMetaFile as any) = jest.fn((fullFilePath: string) => { - return { - defaultProfile: "mybana", - configuration: { - type: "", - schema: { - type: "object", - title: "test profile", - description: "test profile", - properties: { - sum: { - type: "number" - } - }, - required: ["sum"] - } - } - }; - }); - afterEach(() => { - writtenProfile = undefined; // clear any saved profile to not pollute results across tests - }); - - const profileDir = "dummy"; - const testLogger = TestLogger.getTestLogger(); - const profileTypeOne = "banana"; - const profileTypeTwo = "dependencies"; - const profileTypeThree = "differentOptions"; - const addTwoNumbersHandler = __dirname + "/profileHandlers/AddTwoNumbersHandler"; - const doNothingHandler = __dirname + "/profileHandlers/DoNothingHandler"; - const throwErrorHandler = __dirname + "/profileHandlers/ThrowErrorHandler"; - const getTypeConfigurations: () => ICommandProfileTypeConfiguration[] = () => { - return [{ - type: profileTypeOne, - schema: { - type: "object", - title: "test profile", - description: "test profile", - properties: { - sum: { - type: "number" - } - }, - required: ["sum"] - }, - }, { - type: profileTypeTwo, - schema: { - type: "object", - title: "profile with dependencies", - description: "profile with dependencies", - properties: {}, - required: ["dependencies"] - }, - dependencies: [ - {type: profileTypeOne, description: profileTypeOne + " dependency", required: true} - ] - }, - { - type: profileTypeThree, - title: "profile with different option names compare to schema fields", - schema: { - type: "object", - title: "test profile", - description: "test profile", - properties: { - property1: { - type: "number", - optionDefinition: { - name: "differentProperty1", - type: "number", - description: "property1" - } - }, - property2: { - type: "string", - optionDefinition: { - name: "differentProperty2", - type: "string", - description: "property2" - } - }, - hasChild: { - type: "object", - properties: { - hasGrandChild: { - type: "object", - properties: { - grandChild: { - optionDefinition: { - name: "myGrandChild", - type: "string", - description: "my grand child", - } - } - } - } - } - } - }, - required: ["property2"] - }, - }]; - }; - - it("should only load all profiles of the manager type if requested", async () => { - // Mock the profile IO functions - ProfileIO.getAllProfileNames = jest.fn((dir, ext, meta) => { - expect(dir).toContain(profileTypeOne); - return ["prof_banana"]; - }); - - // Create an instance of the manager - const configs = getTypeConfigurations(); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - - // Load "all" profiles - const loads: IProfileLoaded[] = await manager.loadAll({typeOnly: true}); - expect(ProfileIO.getAllProfileNames).toHaveBeenCalledTimes(1); - }); - - it("should take a handler to create a profile from command line arguments, and " + - "the handler should be called and the resulting profile should have the created fields in it.", async () => { - const configs = getTypeConfigurations(); - - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - - configs[0].createProfileFromArgumentsHandler = addTwoNumbersHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const a = 1; - const b = 2; - const profileName = "myprofile"; - const saveResult = await manager.save({ - name: profileName, type: profileTypeOne, - profile: {}, - args: {_: [], $0: "test", a, b}, - overwrite: true - }); - testLogger.info("Save profile result: " + inspect(saveResult)); - expect(saveResult.profile.sum).toEqual(a + b); - expect(writtenProfile.sum).toEqual(a + b); - }); - - it("should take a handler to update a profile from command line arguments, and " + - "the handler should be called and the resulting profile should have the created fields in it.", async () => { - const configs = getTypeConfigurations(); - const oldSum = 55; - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, type: "string") => { - return {name: profileName, type: profileTypeOne, sum: oldSum}; - }); - configs[0].updateProfileFromArgumentsHandler = addTwoNumbersHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const a = 1; - const b = 2; - const profileName = "myprofile"; - const saveResult = await manager.update({ - name: profileName, type: profileTypeOne, - profile: {}, - args: {_: [], $0: "test", a, b} - }); - testLogger.info("Update profile result: " + inspect(saveResult)); - expect(saveResult.profile.sum).toEqual(a + b); - }); - - it("should take a handler to create a profile from command line arguments, but if " + - "the profile handler does not add a field required by the schema, " + - "we should get a validation error", async () => { - const configs = getTypeConfigurations(); - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - configs[0].createProfileFromArgumentsHandler = doNothingHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const a = 1; - const b = 2; - const profileName = "myprofile"; +describe("Basic Profile Manager Constructor", () => { + it("should detect no parms when instantiating", () => { + let error; try { - await manager.save({ - name: profileName, type: profileTypeOne, - profile: {}, - args: {_: [], $0: "test", a, b}, - overwrite: true - }); + new CliProfileManager(undefined as any); } catch (e) { - expect(e.message).toContain("content"); + error = e; + TestLogger.info(error); } + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain("Expect Error: Profile Manager input parms not supplied"); }); - it("should still create a profile properly without providing args", async () => { - const configs = getTypeConfigurations(); - - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - configs[0].createProfileFromArgumentsHandler = doNothingHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const profileName = "myprofile"; - let caughtError; - + it("should detect that no type configuration is supplied", () => { + let error; try { - await manager.save({ - name: profileName, type: profileTypeOne, - profile: {sum: 55}, - overwrite: true + new CliProfileManager({ + typeConfigurations: undefined, + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() }); - } catch (error) { - caughtError = error; + } catch (e) { + error = e; + TestLogger.info(error); } - - expect(caughtError).toBeUndefined(); - }); - - it("should still update a profile properly without providing args", async () => { - const configs = getTypeConfigurations(); - const oldSum = 55; - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, type: "string") => { - return {name: profileName, type: profileTypeOne, sum: oldSum}; - }); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const processSecurePropertiesSpy = jest.spyOn(manager as any, "processSecureProperties"); - const newSum = 66; - const profileName = "myprofile"; - const saveResult = await manager.update({ - name: profileName, type: profileTypeOne, - profile: {sum: newSum} - }); - testLogger.info("Update profile result: " + inspect(saveResult)); - expect(saveResult.profile.sum).toEqual(newSum); - // Should have only processed secure properties once - expect(processSecurePropertiesSpy).toHaveBeenCalledTimes(1); + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain("V1 profiles are no longer read from disk. " + + "You can supply the profile type configurations to the profile manager constructor" + ); }); - it("should still fail profile validation on creation if no args are provided", async () => { - const configs = getTypeConfigurations(); - - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const profileName = "myprofile"; - + it("should detect that the type configuration is an empty array", () => { + let error; try { - await manager.save({ - name: profileName, type: profileTypeOne, - profile: {}, - overwrite: true + new CliProfileManager({ + typeConfigurations: [], + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() }); } catch (e) { - testLogger.warn("Got error as expected:" + inspect(e.stack, {depth: null, breakLength: 40})); - expect(e.message).toContain("content"); + error = e; + TestLogger.info(error); } + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain("V1 profiles are no longer read from disk. " + + "You can supply the profile type configurations to the profile manager constructor" + ); }); - it("should still fail profile validation on update if no args are provided", async () => { - const configs = getTypeConfigurations(); - - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - writtenProfile = profile; - }); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const profileName = "myprofile"; - + it("should detect if the type is undefined", () => { + let error; try { - await manager.update({ - name: profileName, type: profileTypeOne, - profile: {}, - overwrite: true + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: undefined as any, + logger: TestLogger.getTestLogger() }); } catch (e) { - expect(e.message).toContain("content"); + error = e; + TestLogger.info(error); } + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain("Expect Error: No profile type supplied on the profile manager parameters"); }); - it("If we provide a non existent handler to create a profile from command line arguments, " + - "we should get a helpful error.", async () => { - const configs = getTypeConfigurations(); - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - configs[0].createProfileFromArgumentsHandler = __dirname + "/profileHandlers/fakearooni"; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); + it("should detect if the type is blank", () => { + let error; try { - await manager.save({ - name: "badprofile", type: profileTypeOne, - profile: {sum: 2}, - args: {_: [], $0: "test", doesNotMatter: "hi"}, - overwrite: true + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: " ", + logger: TestLogger.getTestLogger() }); } catch (e) { - testLogger.info("Received error as expected: " + inspect(e)); - expect(e.message).toContain("handler"); - expect(e.message.toLowerCase()).toContain("error"); + error = e; + TestLogger.info(error); } + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain("Expect Error: No profile type supplied on the profile manager parameters"); }); - it("If we provide a non existent handler to update a profile from command line arguments, " + - "we should get a helpful error.", async () => { - const configs = getTypeConfigurations(); - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - configs[0].updateProfileFromArgumentsHandler = __dirname + "/profileHandlers/fakearooni"; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); + it("should detect that a type not found within the configurations", () => { + let error; try { - await manager.update({ - name: "badprofile", type: profileTypeOne, - profile: {sum: 2}, - args: {_: [], $0: "test", doesNotMatter: "hi"}, - overwrite: true + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: "bad_apple", + logger: TestLogger.getTestLogger() }); } catch (e) { - testLogger.info("Received error as expected: " + inspect(e)); - expect(e.message).toContain("handler"); - expect(e.message.toLowerCase()).toContain("error"); + error = e; + TestLogger.info(error); } + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toContain( + "Expect Error: Could not locate the profile type configuration for \"bad_apple\" within the input configuration list passed." + ); }); - it("should catch errors thrown by custom profile create handler and expose them " + - "to the user", async () => { - const configs = getTypeConfigurations(); - - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - // do nothing - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, type: "string") => { - return {name: profileName, type: profileTypeOne}; - }); - configs[0].createProfileFromArgumentsHandler = throwErrorHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const a = 1; - const b = 2; - const profileName = "myprofile"; + it("should allow us to instantiate the cli profile manager", () => { + let error; try { - await manager.save({ - name: profileName, type: profileTypeOne, - profile: {}, - args: {_: [], $0: "test", a, b}, - overwrite: true + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() }); + TestLogger.info("Profile Manager Created"); } catch (e) { - testLogger.info("Received error as expected: " + inspect(e)); - expect(e.message).toContain("custom"); - expect(e.message).toContain("handler"); - expect(e.message).toContain("threw"); // expect the output from the error in the handler + error = e; + TestLogger.error(e); } - + expect(error).toBeUndefined(); }); - it("should catch errors thrown by custom profile update handler and expose them " + - "to the user", async () => { - const configs = getTypeConfigurations(); - ProfileIO.writeProfile = jest.fn((fullFilePath: string, profile: IProfile) => { - // do nothing - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, type: "string") => { - return {name: profileName, type: profileTypeOne}; - }); - configs[0].updateProfileFromArgumentsHandler = throwErrorHandler; - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeOne, - logger: testLogger, - typeConfigurations: configs - }); - const a = 1; - const b = 2; - const profileName = "myprofile"; + it("should detect that a schema definition document is attempting to overload 'type'", () => { + const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); + copy[0].schema.properties.type = {type: "boolean"}; + let caughtError; try { - await manager.update({ - name: profileName, type: profileTypeOne, - profile: {}, - args: {_: [], $0: "test", a, b}, - overwrite: true + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() }); - } catch (e) { - testLogger.info("Received error as expected: " + inspect(e)); - expect(e.message).toContain("custom"); - expect(e.message).toContain("handler"); - expect(e.message).toContain("threw"); // expect the output from the error in the handler + } catch (error) { + caughtError = error; } - - }); - it("should create a profile with dependencies if the proper command line arguments are provided", - async () => { - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the dependent profile already exists - }); - const configs = getTypeConfigurations(); - ProfileIO.writeProfile = jest.fn( - (fullFilePath: string, profile: IProfile) => { - // do nothing - }); - ProfileIO.readProfileFile = jest.fn( - (fullFilePath: string, type: "string") => { - return {name: profileName, type: profileTypeOne, sum: 55}; - }); - - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeTwo, - logger: testLogger, - typeConfigurations: configs - }); - const dependentProfileName = "myFirstProfile"; - const profileName = "myprofile"; - - const args: any = {_: [], $0: "test"}; - args[ProfileUtils.getProfileOption(profileTypeOne)] = dependentProfileName; - const saveResult = await manager.save({ - name: profileName, type: profileTypeTwo, - profile: {}, - args, - overwrite: true - }); - expect(saveResult.profile.dependencies[0].name).toEqual(dependentProfileName); - expect(saveResult.profile.dependencies[0].type).toEqual(profileTypeOne); - }); - - it("should be able to map option definitions back to differently named " + - "profile fields on update", async () => { - const configs = getTypeConfigurations(); - const oldSum = 55; - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, - type: "string") => { - return { - name: profileName, - type: profileTypeThree, - sum: oldSum - }; - }); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeThree, - logger: testLogger, - typeConfigurations: configs - }); - - const profileName = "myprofile"; - const property1Value = 5; - const property2Value = "hello"; - const updateResult = await manager.update({ - name: profileName, type: profileTypeThree, - profile: {}, - args: { - _: [], $0: "test", - differentProperty1: property1Value, - differentProperty2: property2Value, - myGrandChild: "johnny" - } - }); - testLogger.info("Update profile result: " + inspect(updateResult, {depth: null})); - expect(updateResult.profile.property1).toEqual(property1Value); - expect(updateResult.profile.property2).toEqual(property2Value); - expect(updateResult.profile.hasChild.hasGrandChild.grandChild).toEqual("johnny"); - }); - - it("should be able to map option definitions back to differently named " + - "profile fields on creation", async () => { - const configs = getTypeConfigurations(); - const oldSum = 55; - (ProfileIO.exists as any) = jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, - type: "string") => { - return { - name: profileName, - type: profileTypeThree, - sum: oldSum - }; - }); - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeThree, - logger: testLogger, - typeConfigurations: configs - }); - - const profileName = "myprofile"; - const property1Value = 5; - const property2Value = "hello"; - const saveResult = await manager.save({ - name: profileName, type: profileTypeThree, - profile: {}, - args: { - _: [], $0: "test", - differentProperty1: property1Value, - differentProperty2: property2Value, - myGrandChild: "johnny" - }, - overwrite: true - }); - testLogger.info("Save profile result: " + inspect(saveResult, {depth: null})); - expect(saveResult.profile.property1).toEqual(property1Value); - expect(saveResult.profile.property2).toEqual(property2Value); - expect(saveResult.profile.hasChild.hasGrandChild.grandChild).toEqual("johnny"); + expect(caughtError).toBeUndefined(); }); - - it("should provide a helpful error message if an error is encountered saving the profile " + - "while updating", async () => { - const configs = getTypeConfigurations(); - const oldSum = 55; - (ProfileIO.exists as any)= jest.fn(() => { - return true; // pretend the profile already exists - }); - ProfileIO.readProfileFile = jest.fn((fullFilePath: string, - type: "string") => { - return { - name: profileName, - type: profileTypeThree, - sum: oldSum - }; - }); - - const manager = new CliProfileManager({ - profileRootDirectory: profileDir, - type: profileTypeThree, - logger: testLogger, - typeConfigurations: configs - }); - const errMessage = "weasel"; - (CliProfileManager.prototype as any).saveProfile = jest.fn(async (parms: ISaveProfileFromCliArgs) => { - throw new ImperativeError({msg: errMessage}); - }); - const profileName = "myprofile"; - const property1Value = 5; - const property2Value = "hello"; + it("should detect that a schema definition document is attempting to overload 'name'", () => { + const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); + copy[0].schema.properties.name = {type: "boolean"}; + let caughtError; try { - await manager.update({ - name: profileName, type: profileTypeThree, - profile: {}, - args: { - _: [], $0: "test", - differentProperty1: property1Value, - differentProperty2: property2Value, - myGrandChild: "johnny" - } + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() }); - } catch (e) { - expect(e.message).toContain(errMessage); - expect(e.message).toContain("profile"); - return; - } - expect("should have encountered an error").toBeFalsy(); - }); - - it("should merge on update if \"merge\" is specified on the parms and no CLI args are specfied", async () => { - const prof = new CliProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: [{ - type: PROFILE_TYPE.STRAWBERRY, - schema: { - type: "object", - title: "test profile for updating on merging", - description: "ditto", - properties: { - myArrayVariable: { - type: "array" - }, - hasNestedArray: { - type: "object" - } - } - } - }], - type: PROFILE_TYPE.STRAWBERRY, - logger: testLogger - }); - const profileA = { - type: PROFILE_TYPE.STRAWBERRY, name: "first", - myArrayVariable: ["old_value1", "oldValue2"], - // test that the array replacement still works on deeply nested fields - hasNestedArray: {hasNestedArray: {hasNestedArray: ["old_value1", "old_value2"]}}, - }; - ProfileIO.writeProfile = jest.fn((path: string, profile: any) => { - // do nothing - }); - ProfileIO.exists = jest.fn((path: string) => { - return path.indexOf("meta") === -1 ? path : undefined; - }); - ProfileIO.readProfileFile = jest.fn((filePath: string, type: string) => { - if (type === PROFILE_TYPE.STRAWBERRY) { - return profileA; - } else { - return { - type: "apple", - name: "thing" - }; - } - }); - const profileB: IProfile = { - myArrayVariable: ["new_value1", "new_value2", "new_value3"], - hasNestedArray: {hasNestedArray: {hasNestedArray: ["new_value1", "new_value2", "new_value3", "new_value4"]}}, - }; - const updateResult = await prof.update({ - type: PROFILE_TYPE.STRAWBERRY, - name: "first", profile: profileB, merge: true - }); - const merged = updateResult.profile; - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.myArrayVariable.length).toEqual(profileB.myArrayVariable.length); - for (const oldValue of profileA.myArrayVariable) { - expect(merged.myArrayVariable.indexOf(oldValue)).toEqual(-1); - } - - for (const oldValue of profileA.hasNestedArray.hasNestedArray.hasNestedArray) { - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.indexOf(oldValue)).toEqual(-1); + } catch (error) { + caughtError = error; } - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.length).toEqual(profileB.hasNestedArray.hasNestedArray.hasNestedArray.length); - expect(merged.hasNestedArray).toEqual(profileB.hasNestedArray); + expect(caughtError).toBeUndefined(); }); - it("should merge on update if \"merge\" is specified on the parms and CLI args are specfied", async () => { - const prof = new CliProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: [{ - type: PROFILE_TYPE.STRAWBERRY, - schema: { - type: "object", - title: "test profile for updating on merging", - description: "ditto", - properties: { - myArrayVariable: { - type: "array", - optionDefinition: { - type: "array", - description: "my array variable", - name: "myArrayVariable" - } - }, - hasNestedArray: { - type: "object", - properties: { - hasNestedArray: { - type: "object", properties: { - hasNestedArray: { - type: "array", - optionDefinition: { - type: "array", - name: "hasNestedArray", - description: "nested array property" - } - } - } - } - } - } - } - } - }], - type: PROFILE_TYPE.STRAWBERRY, - logger: testLogger - }); - const profileA = { - myArrayVariable: ["old_value1", "oldValue2"], - // test that the array replacement still works on deeply nested fields - hasNestedArray: {hasNestedArray: {hasNestedArray: ["old_value1", "old_value2"]}}, - }; - ProfileIO.writeProfile = jest.fn((path: string, profile: any) => { - // do nothing - }); - ProfileIO.exists = jest.fn((path: string) => { - return path.indexOf("meta") === -1 ? path : undefined; - }); - ProfileIO.readProfileFile = jest.fn((filePath: string, type: string) => { - if (type === PROFILE_TYPE.STRAWBERRY) { - return profileA; - } else { - return { - type: "apple", - name: "thing" - }; - } - }); - const profileB: IProfile = { - type: PROFILE_TYPE.STRAWBERRY, - name: "first" - }; - const newArrayVariable = ["new_value1", "new_value2", "new_value3"]; - const newNestedArray = ["new_value1", "new_value2", "new_value3", "new_value4"]; - const updateResult = await prof.update({ - type: PROFILE_TYPE.STRAWBERRY, name: "first", - profile: profileB, args: { - $0: "dummy", _: [], - hasNestedArray: newNestedArray, - myArrayVariable: newArrayVariable, - }, - merge: true - }); - const merged = updateResult.profile; - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.myArrayVariable.length).toEqual(newArrayVariable.length); - for (const oldValue of profileA.myArrayVariable) { - expect(merged.myArrayVariable.indexOf(oldValue)).toEqual(-1); - } - - for (const oldValue of profileA.hasNestedArray.hasNestedArray.hasNestedArray) { - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.indexOf(oldValue)).toEqual(-1); + it("should detect that a schema definition document is attempting to overload 'dependencies'", () => { + const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); + copy[0].schema.properties.dependencies = {type: "boolean"}; + let caughtError; + try { + new CliProfileManager({ + typeConfigurations: ONLY_APPLE, + type: APPLE_PROFILE_TYPE, + logger: TestLogger.getTestLogger() + }); + } catch (error) { + caughtError = error; } - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.length).toEqual(newNestedArray.length); - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray).toEqual(newNestedArray); + expect(caughtError).toBeUndefined(); }); }); diff --git a/packages/imperative/src/cmd/__tests__/profiles/CommandProfileLoader.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/CommandProfileLoader.unit.test.ts index 13852e998d..0f5cea376b 100644 --- a/packages/imperative/src/cmd/__tests__/profiles/CommandProfileLoader.unit.test.ts +++ b/packages/imperative/src/cmd/__tests__/profiles/CommandProfileLoader.unit.test.ts @@ -9,23 +9,14 @@ * */ -jest.mock("../../../profiles/src/BasicProfileManager"); -jest.mock("../../../profiles/src/BasicProfileManagerFactory"); -jest.mock("../../../utilities/src/ImperativeConfig"); -jest.mock("../../../logger/src/LoggerUtils"); import { CommandProfileLoader } from "../../src/profiles/CommandProfileLoader"; import { ICommandDefinition } from "../../src/doc/ICommandDefinition"; -import { BasicProfileManager } from "../../../profiles/src/BasicProfileManager"; import { TestLogger } from "../../../../__tests__/src/TestLogger"; import { CommandProfiles } from "../../src/profiles/CommandProfiles"; import { ImperativeError } from "../../../error"; -import { BasicProfileManagerFactory, IProfile, IProfileLoaded } from "../../../profiles"; -import { ImperativeConfig } from "../../../utilities"; - -const TEST_PROFILES_DIR = "/test/data/profiles/fake"; +import { IProfile, IProfileLoaded } from "../../../profiles"; const PROFILE_BANANA_TYPE: string = "banana"; -const STRAWBERRY_PROFILE_TYPE: string = "strawberry"; const SAMPLE_COMMAND_NO_PROFILE: ICommandDefinition = { name: PROFILE_BANANA_TYPE, @@ -42,33 +33,11 @@ const SAMPLE_COMMAND_PROFILE: ICommandDefinition = { } }; -const SAMPLE_COMMAND_TWO_PROFILE_TYPES: ICommandDefinition = { - name: "bunch", - description: "The banana command", - type: "command", - profile: { - required: [PROFILE_BANANA_TYPE, STRAWBERRY_PROFILE_TYPE] - } -}; - -const SAMPLE_COMMAND_TWO_PROFILE_TYPES_ONE_OPTIONAL: ICommandDefinition = { - name: "bunch", - description: "The banana command", - type: "command", - profile: { - required: [PROFILE_BANANA_TYPE], - optional: [STRAWBERRY_PROFILE_TYPE] - } -}; - -const sampleRoot = __dirname + "/__tests__/__results__/data/"; - describe("Command Profile Loader", () => { it("should allow us to create an instance", () => { const loader = CommandProfileLoader.loader({ commandDefinition: SAMPLE_COMMAND_NO_PROFILE, - profileManagerFactory: new BasicProfileManagerFactory(TEST_PROFILES_DIR), logger: TestLogger.getTestLogger() }); expect(loader).toBeDefined(); @@ -77,7 +46,6 @@ describe("Command Profile Loader", () => { it("should allow us to create an instance and load nothing", async () => { const loaded: CommandProfiles = await CommandProfileLoader.loader({ commandDefinition: SAMPLE_COMMAND_NO_PROFILE, - profileManagerFactory: new BasicProfileManagerFactory(TEST_PROFILES_DIR), logger: TestLogger.getTestLogger() }).loadProfiles({ _: undefined as any, $0: undefined as any }); expect(loaded).toBeDefined(); @@ -86,26 +54,22 @@ describe("Command Profile Loader", () => { it("should allow us to create an instance without a logger", () => { const loader = CommandProfileLoader.loader({ commandDefinition: SAMPLE_COMMAND_NO_PROFILE, - profileManagerFactory: new BasicProfileManagerFactory(TEST_PROFILES_DIR) }); expect(loader).toBeDefined(); }); it("should allow us to create an instance (directly with constructor)", () => { - const loader = new CommandProfileLoader(SAMPLE_COMMAND_NO_PROFILE, - new BasicProfileManagerFactory(TEST_PROFILES_DIR)); + const loader = new CommandProfileLoader(SAMPLE_COMMAND_NO_PROFILE); expect(loader).toBeDefined(); }); it("should detect a bad logger instance", () => { let error; try { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); let logger: any = TestLogger.getTestLogger(); logger = {bad: "logger"}; CommandProfileLoader.loader({ commandDefinition: SAMPLE_COMMAND_NO_PROFILE, - profileManagerFactory: manager, logger }); } catch (e) { @@ -113,33 +77,14 @@ describe("Command Profile Loader", () => { } expect(error).toBeDefined(); expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); + expect(error.message).toContain('Expect Error: Could not construct the profile loader. The "logger" supplied is not of type Logger.'); }); it("should detect missing command definitions when creating the loader", () => { let error; try { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); CommandProfileLoader.loader({ commandDefinition: undefined as any, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect missing profile manager when creating the loader", () => { - let error; - try { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_NO_PROFILE, - profileManagerFactory: undefined as any, logger: TestLogger.getTestLogger() }); } catch (e) { @@ -147,35 +92,10 @@ describe("Command Profile Loader", () => { } expect(error).toBeDefined(); expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); + expect(error.message).toContain("Expect Error: Could not construct the profile loader. No command definition supplied."); }); - it("should not load old profiles when in team-config mode", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - - // pretend that we have a team config - ImperativeConfig.instance.config = { - exists: true - } as any; - + it("should never read V1 profiles", async () => { const emptyProfileMap: Map = new Map(); const emptyProfileMetaMap: Map = new Map(); const noProfilesLoaded = new CommandProfiles(emptyProfileMap, emptyProfileMetaMap); @@ -183,413 +103,9 @@ describe("Command Profile Loader", () => { // because we have a team config, we should load no old-scemptyProfileMaphool profiles const loadedCmdProfiles: CommandProfiles = await CommandProfileLoader.loader({ commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, logger: TestLogger.getTestLogger() }).loadProfiles({ _: undefined as any, $0: undefined as any }); expect(loadedCmdProfiles).toEqual(noProfilesLoaded); - - // restore to not having a team config for future tests - ImperativeConfig.instance.config = { - exists: false - } as any; - }); - - it("should allow us to load a required profile", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({ _: undefined as any, $0: undefined as any }); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - }); - - it("should percolate the load error to the caller", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => { - throw new ImperativeError({msg: `An error occurred during the load.`}); - }); - let error; - try { - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({ _: undefined as any, $0: undefined as any }); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should react properly if the profile manager does not return an expected result for default", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({} as any )); - let error; - try { - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({ _: undefined as any, $0: undefined as any }); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should react properly if the profile manager does not return an expected result", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({} as any)); - let error; - try { - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({ "_": undefined as any, "$0": undefined as any, "banana-profile": "tasty"}); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to load a required profile by name", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty"}); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - }); - - it("should allow us to load a required profile by name with a dependency", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManager = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - return profManager; - }); - profManager.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - }, - dependenciesLoaded: true, - dependencyLoadResponses: [ - { - message: "Profile Loaded", - type: STRAWBERRY_PROFILE_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "red", - type: STRAWBERRY_PROFILE_TYPE, - }, - } - ] - })); - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty"}); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - expect(response.get(STRAWBERRY_PROFILE_TYPE)).toMatchSnapshot(); - }); - - it("should allow us to load two different required types", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManagerBanana = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - const profManagerStrawberry = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - if (type === PROFILE_BANANA_TYPE) { - return profManagerBanana; - } - if (type === STRAWBERRY_PROFILE_TYPE) { - return profManagerStrawberry; - } - return undefined as any; - }); - profManagerBanana.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - profManagerStrawberry.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: STRAWBERRY_PROFILE_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "red", - type: STRAWBERRY_PROFILE_TYPE, - } - })); - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_TWO_PROFILE_TYPES, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty", "strawberry-profile": "red"}); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - expect(response.get(STRAWBERRY_PROFILE_TYPE)).toMatchSnapshot(); - }); - - it("should percolate the error if a required profile for one type is not found", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManagerBanana = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - const profManagerStrawberry = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - if (type === PROFILE_BANANA_TYPE) { - return profManagerBanana; - } - if (type === STRAWBERRY_PROFILE_TYPE) { - return profManagerStrawberry; - } - return undefined as any; - }); - profManagerBanana.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - profManagerStrawberry.load = jest.fn((parms) => { - throw new ImperativeError({msg: `Not found`}); - }); - let error; - try { - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_TWO_PROFILE_TYPES, - profileManagerFactory: manager, - logger: TestLogger.getTestLogger() - }) - .loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty", "strawberry-profile": "red"}); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should handle multiple loads of the same type", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManagerBanana = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - manager.getManager = jest.fn((type) => { - if (type === PROFILE_BANANA_TYPE) { - return profManagerBanana; - } - return undefined as any; - }); - profManagerBanana.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - }, - dependenciesLoaded: true, - dependencyLoadResponses: [ - { - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "great", - failNotFound: true, - profile: { - name: "great", - type: PROFILE_BANANA_TYPE, - }, - dependenciesLoaded: true, - dependencyLoadResponses: [ - { - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "awesome", - failNotFound: true, - profile: { - name: "awesome", - type: PROFILE_BANANA_TYPE, - }, - } - ] - } - ] - })); - // commandDefinition: SAMPLE_COMMAND_TWO_PROFILE_TYPES_ONE_OPTIONAL, - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_PROFILE, - profileManagerFactory: manager, logger: - TestLogger.getTestLogger() - }).loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty"}); - expect(response.getAll(PROFILE_BANANA_TYPE)[0]).toMatchSnapshot(); - expect(response.getAll(PROFILE_BANANA_TYPE)[1]).toMatchSnapshot(); - expect(response.getAll(PROFILE_BANANA_TYPE)[2]).toMatchSnapshot(); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - expect(response.getAll(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - }); - - it("should handle load of required and optional profiles", async () => { - const manager = new BasicProfileManagerFactory(TEST_PROFILES_DIR); - const profManagerBanana = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: PROFILE_BANANA_TYPE - }); - const profManagerStrawberry = new BasicProfileManager({ - logger: TestLogger.getTestLogger(), - profileRootDirectory: sampleRoot, - type: STRAWBERRY_PROFILE_TYPE - }); - manager.getManager = jest.fn((type) => { - if (type === PROFILE_BANANA_TYPE) { - return profManagerBanana; - } - if (type === STRAWBERRY_PROFILE_TYPE) { - return profManagerStrawberry; - } - return undefined as any; - }); - profManagerBanana.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: PROFILE_BANANA_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "tasty", - type: PROFILE_BANANA_TYPE, - } - })); - profManagerStrawberry.load = jest.fn((parms) => Promise.resolve({ - message: "Profile Loaded", - type: STRAWBERRY_PROFILE_TYPE, - name: "tasty", - failNotFound: true, - profile: { - name: "red", - type: STRAWBERRY_PROFILE_TYPE, - } - })); - - const response = await CommandProfileLoader.loader({ - commandDefinition: SAMPLE_COMMAND_TWO_PROFILE_TYPES_ONE_OPTIONAL, - profileManagerFactory: manager, logger: - TestLogger.getTestLogger() - }).loadProfiles({"_": undefined as any, "$0": undefined as any, "banana-profile": "tasty", "strawberry-profile": "red"}); - expect(response.get(PROFILE_BANANA_TYPE)).toMatchSnapshot(); - expect(response.get(STRAWBERRY_PROFILE_TYPE)).toMatchSnapshot(); }); }); diff --git a/packages/imperative/src/cmd/__tests__/profiles/CommandProfiles.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/CommandProfiles.unit.test.ts index bf683a2eaa..48352581fc 100644 --- a/packages/imperative/src/cmd/__tests__/profiles/CommandProfiles.unit.test.ts +++ b/packages/imperative/src/cmd/__tests__/profiles/CommandProfiles.unit.test.ts @@ -27,110 +27,7 @@ describe("Command Profiles", () => { expect(caughtError).toBeUndefined(); }); - it("should detect missing parameters", () => { - let error; - try { - const profiles = new CommandProfiles(undefined); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the parameters are not a map", () => { - let error; - try { - const map = { not: "a-map" }; - new CommandProfiles(map as any); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should accept a profile map and allow us to retrieve them", () => { - const map = new Map(); - map.set(BANANA_PROFILE_TYPE, [{ - name: "tasty", - type: BANANA_PROFILE_TYPE, - age: 1 - }]); - map.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - age: 1 - }, { - name: "awesome", - type: STRAWBERRY_PROFILE_TYPE, - age: 2 - }]); - const profiles = new CommandProfiles(map); - expect(profiles.getAll(BANANA_PROFILE_TYPE)).toMatchSnapshot(); - expect(profiles.getAll(STRAWBERRY_PROFILE_TYPE)).toMatchSnapshot(); - expect(profiles.get(STRAWBERRY_PROFILE_TYPE)).toMatchSnapshot(); - expect(profiles.get(BANANA_PROFILE_TYPE)).toMatchSnapshot(); - }); - - it("should throw an error if get does not have the profile type in the map", () => { - const map = new Map(); - map.set(BANANA_PROFILE_TYPE, [{ - name: "tasty", - type: BANANA_PROFILE_TYPE, - age: 1 - }]); - let error; - try { - const profiles = new CommandProfiles(map); - profiles.get(STRAWBERRY_PROFILE_TYPE); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - expect(error.additionalDetails).toMatchSnapshot(); - }); - - it("should not throw an error if get does not have the profile type but throw not found is false", () => { - const map = new Map(); - map.set(BANANA_PROFILE_TYPE, [{ - name: "tasty", - type: BANANA_PROFILE_TYPE, - age: 1 - }]); - let error; - let response; - try { - const profiles = new CommandProfiles(map); - response = profiles.get(STRAWBERRY_PROFILE_TYPE, false); - } catch (e) { - error = e; - } - expect(error).toBeUndefined(); - expect(response).toBeUndefined(); - }); - - it("should accept a profile map and allow us to retrieve by name", () => { - const map = new Map(); - map.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - age: 1 - }, { - name: "awesome", - type: STRAWBERRY_PROFILE_TYPE, - age: 2 - }]); - const profiles = new CommandProfiles(map); - const awesome = profiles.get(STRAWBERRY_PROFILE_TYPE, true, "awesome"); - expect(awesome).toMatchSnapshot(); - }); - - it("should accept a loaded profile map and allow us to retrieve by name", () => { + it("should allow us to create an instance with map values", () => { const map = new Map(); map.set(STRAWBERRY_PROFILE_TYPE, [{ name: "great", @@ -160,84 +57,33 @@ describe("Command Profiles", () => { message: "too old", failNotFound: false }]); - const profiles = new CommandProfiles(map, metaMap); - const awesome = profiles.getMeta(STRAWBERRY_PROFILE_TYPE, false, "great"); - expect(awesome).toMatchSnapshot(); - }); - it("should accept a loaded profile map and allow us to retrieve without a name", () => { - const map = new Map(); - map.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - age: 1 - }, { - name: "awesome", - type: STRAWBERRY_PROFILE_TYPE, - age: 2 - }]); - const metaMap = new Map(); - metaMap.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - profile: { - age: 1 - }, - message: "just right", - failNotFound: false - }, - { - name: "gross", - type: STRAWBERRY_PROFILE_TYPE, - profile: { - age: 3 - }, - message: "too old", - failNotFound: false - }]); const profiles = new CommandProfiles(map, metaMap); - const awesome = profiles.getMeta(STRAWBERRY_PROFILE_TYPE, false, null); - expect(awesome).toMatchSnapshot(); + expect(profiles).toMatchSnapshot(); }); - it("should accept a loaded profile map and allow us to retrieve with a name and fail", () => { - const map = new Map(); - map.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - age: 1 - }, { - name: "awesome", - type: STRAWBERRY_PROFILE_TYPE, - age: 2 - }]); - const metaMap = new Map(); - metaMap.set(STRAWBERRY_PROFILE_TYPE, [{ - name: "great", - type: STRAWBERRY_PROFILE_TYPE, - profile: { - age: 1 - }, - message: "just right", - failNotFound: true - }, - { - name: "gross", - type: STRAWBERRY_PROFILE_TYPE, - profile: { - age: 3 - }, - message: "too old", - failNotFound: true - }]); - const profiles = new CommandProfiles(map, metaMap); + it("should detect missing parameters", () => { + let error; + try { + new CommandProfiles(undefined); + } catch (e) { + error = e; + } + expect(error).toBeDefined(); + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toMatchSnapshot(); + }); - let err; + it("should detect that the parameters are not a map", () => { + let error; try { - const awesome = profiles.getMeta("unknown", true, "tasty"); - } catch (thrownError) { - err = thrownError; + const map = { not: "a-map" }; + new CommandProfiles(map as any); + } catch (e) { + error = e; } - expect(err.message).toMatchSnapshot(); + expect(error).toBeDefined(); + expect(error instanceof ImperativeError).toBe(true); + expect(error.message).toMatchSnapshot(); }); }); diff --git a/packages/imperative/src/profiles/__tests__/TestConstants.ts b/packages/imperative/src/cmd/__tests__/profiles/TestConstants.ts similarity index 99% rename from packages/imperative/src/profiles/__tests__/TestConstants.ts rename to packages/imperative/src/cmd/__tests__/profiles/TestConstants.ts index 9ad82d05c9..1258fa22a0 100644 --- a/packages/imperative/src/profiles/__tests__/TestConstants.ts +++ b/packages/imperative/src/cmd/__tests__/profiles/TestConstants.ts @@ -9,7 +9,7 @@ * */ -import { IProfileTypeConfiguration } from "../src/doc/config/IProfileTypeConfiguration"; +import { IProfileTypeConfiguration } from "../../../profiles/src/doc/config/IProfileTypeConfiguration"; export const TEST_PROFILE_ROOT_DIR: string = "__tests__/__results__/test_profiles/root/dir/"; diff --git a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CliProfileManager.credentials.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CliProfileManager.credentials.unit.test.ts.snap deleted file mode 100644 index 812cc058da..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CliProfileManager.credentials.unit.test.ts.snap +++ /dev/null @@ -1,45 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Cli Profile Manager Credential Manager functionality Load operation should not attempt to load secure fields if no credential manager is present 1`] = ` -Object { - "name": "My-secure-orange", - "password": null, - "secureBox": Object { - "myCode": "managed by", - "myEmptyMiniBox": Object { - "emptyMe": null, - }, - "myFlag": "managed by", - "myMiniBox": Object { - "miniMe": null, - }, - "myPhone": "managed by", - "myPhrase": "managed by", - "mySet": "managed by", - }, - "type": "secure-orange", - "username": "username", -} -`; - -exports[`Cli Profile Manager Credential Manager functionality Load operation should not load credentials from a profile if noSecure is specified 1`] = ` -Object { - "name": "My-secure-orange", - "password": null, - "secureBox": Object { - "myCode": "managed by", - "myEmptyMiniBox": Object { - "emptyMe": null, - }, - "myFlag": "managed by", - "myMiniBox": Object { - "miniMe": null, - }, - "myPhone": "managed by", - "myPhrase": "managed by", - "mySet": "managed by", - }, - "type": "secure-orange", - "username": "username", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfileLoader.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfileLoader.unit.test.ts.snap deleted file mode 100644 index f82bee987d..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfileLoader.unit.test.ts.snap +++ /dev/null @@ -1,116 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Command Profile Loader should allow us to load a required profile 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should allow us to load a required profile by name 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should allow us to load a required profile by name with a dependency 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should allow us to load a required profile by name with a dependency 2`] = ` -Object { - "name": "red", - "type": "strawberry", -} -`; - -exports[`Command Profile Loader should allow us to load two different required types 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should allow us to load two different required types 2`] = ` -Object { - "name": "red", - "type": "strawberry", -} -`; - -exports[`Command Profile Loader should detect a bad logger instance 1`] = `"Expect Error: Could not construct the profile loader. The \\"logger\\" supplied is not of type Logger."`; - -exports[`Command Profile Loader should detect missing command definitions when creating the loader 1`] = `"Expect Error: Could not construct the profile loader. No command definition supplied."`; - -exports[`Command Profile Loader should detect missing profile manager when creating the loader 1`] = `"Expect Error: Could not construct the profile loader. No profile factory supplied."`; - -exports[`Command Profile Loader should handle load of required and optional profiles 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should handle load of required and optional profiles 2`] = ` -Object { - "name": "red", - "type": "strawberry", -} -`; - -exports[`Command Profile Loader should handle multiple loads of the same type 1`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should handle multiple loads of the same type 2`] = ` -Object { - "name": "great", - "type": "banana", -} -`; - -exports[`Command Profile Loader should handle multiple loads of the same type 3`] = ` -Object { - "name": "awesome", - "type": "banana", -} -`; - -exports[`Command Profile Loader should handle multiple loads of the same type 4`] = ` -Object { - "name": "tasty", - "type": "banana", -} -`; - -exports[`Command Profile Loader should handle multiple loads of the same type 5`] = ` -Array [ - Object { - "name": "tasty", - "type": "banana", - }, - Object { - "name": "great", - "type": "banana", - }, - Object { - "name": "awesome", - "type": "banana", - }, -] -`; - -exports[`Command Profile Loader should percolate the error if a required profile for one type is not found 1`] = `"Not found"`; - -exports[`Command Profile Loader should percolate the load error to the caller 1`] = `"An error occurred during the load."`; - -exports[`Command Profile Loader should react properly if the profile manager does not return an expected result 1`] = `"Unexpected internal load error: The profile \\"tasty\\" was not loaded by the profile manager."`; - -exports[`Command Profile Loader should react properly if the profile manager does not return an expected result for default 1`] = `"Unexpected internal load error: The profile \\"default requested\\" was not loaded by the profile manager."`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfiles.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfiles.unit.test.ts.snap index 7b5f0b59bb..ce0dc5c975 100644 --- a/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfiles.unit.test.ts.snap +++ b/packages/imperative/src/cmd/__tests__/profiles/__snapshots__/CommandProfiles.unit.test.ts.snap @@ -1,88 +1,46 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Command Profiles should accept a loaded profile map and allow us to retrieve by name 1`] = ` -Object { - "failNotFound": false, - "message": "just right", - "name": "great", - "profile": Object { - "age": 1, +exports[`Command Profiles should allow us to create an instance with map values 1`] = ` +CommandProfiles { + "mMap": Map { + "strawberry" => Array [ + Object { + "age": 1, + "name": "great", + "type": "strawberry", + }, + Object { + "age": 2, + "name": "awesome", + "type": "strawberry", + }, + ], }, - "type": "strawberry", -} -`; - -exports[`Command Profiles should accept a loaded profile map and allow us to retrieve with a name and fail 1`] = `"Internal Error: No profiles of type \\"unknown\\" were loaded for this command."`; - -exports[`Command Profiles should accept a loaded profile map and allow us to retrieve without a name 1`] = ` -Object { - "failNotFound": false, - "message": "just right", - "name": "great", - "profile": Object { - "age": 1, + "mMetaMap": Map { + "strawberry" => Array [ + Object { + "failNotFound": false, + "message": "just right", + "name": "great", + "profile": Object { + "age": 1, + }, + "type": "strawberry", + }, + Object { + "failNotFound": false, + "message": "too old", + "name": "gross", + "profile": Object { + "age": 3, + }, + "type": "strawberry", + }, + ], }, - "type": "strawberry", -} -`; - -exports[`Command Profiles should accept a profile map and allow us to retrieve by name 1`] = ` -Object { - "age": 2, - "name": "awesome", - "type": "strawberry", -} -`; - -exports[`Command Profiles should accept a profile map and allow us to retrieve them 1`] = ` -Array [ - Object { - "age": 1, - "name": "tasty", - "type": "banana", - }, -] -`; - -exports[`Command Profiles should accept a profile map and allow us to retrieve them 2`] = ` -Array [ - Object { - "age": 1, - "name": "great", - "type": "strawberry", - }, - Object { - "age": 2, - "name": "awesome", - "type": "strawberry", - }, -] -`; - -exports[`Command Profiles should accept a profile map and allow us to retrieve them 3`] = ` -Object { - "age": 1, - "name": "great", - "type": "strawberry", -} -`; - -exports[`Command Profiles should accept a profile map and allow us to retrieve them 4`] = ` -Object { - "age": 1, - "name": "tasty", - "type": "banana", } `; exports[`Command Profiles should detect missing parameters 1`] = `"Expect Error: Command Profiles Internal Error: No map was supplied."`; exports[`Command Profiles should detect that the parameters are not a map 1`] = `"Expect Error: Command Profiles Internal Error: The \\"map\\" supplied is not an instance of a map."`; - -exports[`Command Profiles should throw an error if get does not have the profile type in the map 1`] = `"Internal Error: No profiles of type \\"strawberry\\" were loaded for this command."`; - -exports[`Command Profiles should throw an error if get does not have the profile type in the map 2`] = ` -"This error can occur for one of two reasons: - - The \\"profile\\" property on the command definition document does NOT specify the requested profile type - - The profile type is marked \\"optional\\", no profiles of type \\"strawberry\\" have been created, and the command handler requested a profile of type \\"strawberry\\" with \\"failNotFound=true\\"" -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/CompleteProfilesGroupBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/CompleteProfilesGroupBuilder.unit.test.ts deleted file mode 100644 index 04d7fe60e2..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/CompleteProfilesGroupBuilder.unit.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { ImperativeConfig } from "../../../../utilities"; -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { CompleteProfilesGroupBuilder } from "../../../../imperative/src/profiles/builders/CompleteProfilesGroupBuilder"; - -describe("Complete Profiles Group Builder", () => { - const logger = TestLogger.getTestLogger(); - - // pretend that we have a team config - (ImperativeConfig.instance.config as any) = { - exists: true, - formMainConfigPathNm: jest.fn(() => { - return "zowe.config.json"; - }) - }; - - it("should provide a valid command definition for the " + - "complete auto generated profile group if passed a valid " + - "profile configuration document", () => { - let commands = CompleteProfilesGroupBuilder.getProfileGroup(testBuilderProfiles, logger); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfileBuilderTestConstants.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfileBuilderTestConstants.ts deleted file mode 100644 index c282ed3626..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfileBuilderTestConstants.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ICommandDefinition } from "../../../src/doc/ICommandDefinition"; -import { ICommandProfileTypeConfiguration } from "../../../../cmd/src/doc/profiles/definition/ICommandProfileTypeConfiguration"; - -export const testBuilderProfiles: ICommandProfileTypeConfiguration[] = [ - { - type: "type-a", - schema: { - title: "Type A profile", - type: "object", - description: "Type A profile for builder tests", - properties: { - age: { - type: "number", - optionDefinition: { - name: "age", - type: "number", - description: "The age of the profile" - } - } - } - }, - validationPlanModule: "dummy" - }, - { - type: "type-b", - schema: { - title: "Type B profile", - type: "object", - description: "Type B profile for builder tests", - properties: { - age: { - type: "number", - optionDefinition: { - name: "legs", - type: "number", - description: "The number of legs" - } - } - } - } - } -]; - -/** - * Delete handlers from a command definition since the absolute path is different per - * machine - * @param {ICommandDefinition} command - the definition with the handlers removed - */ -export const deleteHandlerPaths = (command: ICommandDefinition) => { - command = JSON.parse(JSON.stringify(command)); // copy the command - delete command.handler; - const newChildren = []; - for (const child of command.children || []) { - newChildren.push(deleteHandlerPaths(child)); - } - command.children = newChildren; - return command; -}; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesCreateCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesCreateCommandBuilder.unit.test.ts deleted file mode 100644 index 68c571efb2..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesCreateCommandBuilder.unit.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesCreateCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesCreateCommandBuilder"; - -describe("Profile Create Command Builder", () => { - const logger = TestLogger.getTestLogger(); - it("should provide a valid command definition for the " + - "profile create command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesCreateCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); - - it("should expose options for nested properties", () => { - const command = new ProfilesCreateCommandBuilder("test", - logger, { - type: "test", - schema: { - title: "Type A profile", - type: "object", - description: "Type A profile for builder tests", - properties: { - myParent: { - type: "object", - properties: { - middleProperty: { - type: "object", - properties: { - myNestedProperty: { - optionDefinition: { - description: "The nested property", - type: "string", - name: "nested", - required: true - }, - type: "string" - } - } - } - } - }, - } - }, - validationPlanModule: "dummy" - }).buildFull(); - let nestedOptionFound = false; - for (const option of command.options) { - if (option.name === "nested") { - nestedOptionFound = true; - break; - } - } - expect(nestedOptionFound).toEqual(true); - }); - - it("should expose multiple options for nested properties", () => { - const command = new ProfilesCreateCommandBuilder("test", - logger, { - type: "test", - schema: { - title: "Type A profile", - type: "object", - description: "Type A profile for builder tests", - properties: { - myParent: { - type: "object", - properties: { - middleProperty: { - type: "object", - properties: { - myNestedProperty: { - optionDefinitions: [{ - description: "The first nested property", - type: "string", - name: "nested1", - required: true - }, { - description: "The second nested property", - type: "string", - name: "nested2", - required: true - }], - type: "string" - } - } - } - } - }, - } - }, - validationPlanModule: "dummy" - }).buildFull(); - let nestedOption1Found = false; - let nestedOption2Found = false; - for (const option of command.options) { - if (option.name === "nested1") { - nestedOption1Found = true; - } else if (option.name === "nested2") { - nestedOption2Found = true; - } - } - expect(nestedOption1Found).toEqual(true); - expect(nestedOption2Found).toEqual(true); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesDeleteCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesDeleteCommandBuilder.unit.test.ts deleted file mode 100644 index 3586e80ed5..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesDeleteCommandBuilder.unit.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesDeleteCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesDeleteCommandBuilder"; -import { ImperativeConfig } from "../../../../utilities"; - -describe("Profile Delete Command Builder", () => { - const logger = TestLogger.getTestLogger(); - - // pretend that we have a team config - (ImperativeConfig.instance.config as any) = { - exists: true, - formMainConfigPathNm: jest.fn(() => { - return "zowe.config.json"; - }) - }; - - it("should provide a valid command definition for the " + - "profile delete command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesDeleteCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesListCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesListCommandBuilder.unit.test.ts deleted file mode 100644 index 8b12c110ca..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesListCommandBuilder.unit.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesListCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesListCommandBuilder"; - - -describe("Profile List Command Builder", () => { - const logger = TestLogger.getTestLogger(); - it("should provide a valid command definition for the " + - "profile list command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesListCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesSetCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesSetCommandBuilder.unit.test.ts deleted file mode 100644 index 4708f59ac6..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesSetCommandBuilder.unit.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesSetCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesSetCommandBuilder"; - -describe("Profile Set Command Builder", () => { - const logger = TestLogger.getTestLogger(); - it("should provide a valid command definition for the " + - "profile set command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesSetCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesShowDependenciesCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesShowDependenciesCommandBuilder.unit.test.ts deleted file mode 100644 index d40c6aa50d..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesShowDependenciesCommandBuilder.unit.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesShowDependenciesCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesShowDependenciesCommandBuilder"; - -describe("Profile Show Dependencies Command Builder", () => { - const logger = TestLogger.getTestLogger(); - it("should provide a valid command definition for the " + - "profile show dependencies command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesShowDependenciesCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesUpdateCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesUpdateCommandBuilder.unit.test.ts deleted file mode 100644 index b914a10749..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesUpdateCommandBuilder.unit.test.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesUpdateCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesUpdateCommandBuilder"; - -describe("Profile Update Command Builder", () => { - const logger = TestLogger.getTestLogger(); - it("should provide a valid command definition for the " + - "profile update command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesUpdateCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); - - it("should expose options for nested properties", () => { - const command = new ProfilesUpdateCommandBuilder("test", - logger, { - type: "test", - schema: { - title: "Type A profile", - type: "object", - description: "Type A profile for builder tests", - properties: { - myParent: { - type: "object", - properties: { - middleProperty: { - type: "object", - properties: { - myNestedProperty: { - optionDefinition: { - description: "The nested property", - type: "string", - name: "nested", - required: true - }, - type: "string" - } - } - } - } - }, - } - }, - validationPlanModule: "dummy" - }).buildFull(); - let nestedOptionFound = false; - for (const option of command.options) { - if (option.name === "nested") { - nestedOptionFound = true; - break; - } - } - expect(nestedOptionFound).toEqual(true); - }); - - it("should expose multiple options for nested properties", () => { - const command = new ProfilesUpdateCommandBuilder("test", - logger, { - type: "test", - schema: { - title: "Type A profile", - type: "object", - description: "Type A profile for builder tests", - properties: { - myParent: { - type: "object", - properties: { - middleProperty: { - type: "object", - properties: { - myNestedProperty: { - optionDefinitions: [{ - description: "The first nested property", - type: "string", - name: "nested1", - required: true - }, { - description: "The second nested property", - type: "string", - name: "nested2", - required: true - }], - type: "string" - } - } - } - } - }, - } - }, - validationPlanModule: "dummy" - }).buildFull(); - let nestedOption1Found = false; - let nestedOption2Found = false; - for (const option of command.options) { - if (option.name === "nested1") { - nestedOption1Found = true; - } else if (option.name === "nested2") { - nestedOption2Found = true; - } - } - expect(nestedOption1Found).toEqual(true); - expect(nestedOption2Found).toEqual(true); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesValidateCommandBuilder.unit.test.ts b/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesValidateCommandBuilder.unit.test.ts deleted file mode 100644 index b0111b8003..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/ProfilesValidateCommandBuilder.unit.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { deleteHandlerPaths, testBuilderProfiles } from "./ProfileBuilderTestConstants"; -import { TestLogger } from "../../../../../__tests__/src/TestLogger"; -import { ProfilesValidateCommandBuilder } from "../../../../imperative/src/profiles/builders/ProfilesValidateCommandBuilder"; -import { ImperativeConfig } from "../../../../utilities"; - -describe("Profile Validate Command Builder", () => { - const logger = TestLogger.getTestLogger(); - - // pretend that we have a team config - (ImperativeConfig.instance.config as any) = { - exists: true, - formMainConfigPathNm: jest.fn(() => { - return "zowe.config.json"; - }) - }; - - it("should provide a valid command definition for the " + - "profile validate command based on our test profile type", () => { - const firstProfileType = testBuilderProfiles[0]; - let commands = new ProfilesValidateCommandBuilder(firstProfileType.type, logger, firstProfileType).buildFull(); - commands = deleteHandlerPaths(commands); - expect(commands).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/CompleteProfilesGroupBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/CompleteProfilesGroupBuilder.unit.test.ts.snap deleted file mode 100644 index b4b8b367f6..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/CompleteProfilesGroupBuilder.unit.test.ts.snap +++ /dev/null @@ -1,479 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Complete Profiles Group Builder should provide a valid command definition for the complete auto generated profile group if passed a valid profile configuration document 1`] = ` -Object { - "children": Array [ - Object { - "aliases": Array [ - "cre", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config init' command", - "description": "Type A profile for builder tests", - "name": "type-a-profile", - "options": Array [ - Object { - "description": "The age of the profile", - "name": "age", - "type": "number", - }, - Object { - "aliases": Array [ - "ow", - ], - "description": "Overwrite the type-a profile when a profile of the same name exists.", - "name": "overwrite", - "type": "boolean", - }, - Object { - "aliases": Array [ - "dd", - ], - "description": "Disable populating profile values of undefined properties with default values.", - "name": "disable-defaults", - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-a profile. You can load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Create a type-a profile", - "type": "command", - }, - Object { - "aliases": Array [ - "type-b", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-b", - }, - "deprecatedReplacement": "The 'config init' command", - "description": "Type B profile for builder tests", - "name": "type-b-profile", - "options": Array [ - Object { - "description": "The number of legs", - "name": "legs", - "type": "number", - }, - Object { - "aliases": Array [ - "ow", - ], - "description": "Overwrite the type-b profile when a profile of the same name exists.", - "name": "overwrite", - "type": "boolean", - }, - Object { - "aliases": Array [ - "dd", - ], - "description": "Disable populating profile values of undefined properties with default values.", - "name": "disable-defaults", - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-b profile. You can load this profile by using the name on commands that support the \\"--type-b-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Create a type-b profile", - "type": "command", - }, - ], - "deprecatedReplacement": "The 'config init' command", - "description": "Create new configuration profiles.", - "name": "create", - "summary": "Create new configuration profiles", - "type": "group", - }, - Object { - "aliases": Array [ - "upd", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "Type A profile for builder tests", - "name": "type-a-profile", - "options": Array [ - Object { - "absenceImplications": null, - "description": "The age of the profile", - "implies": null, - "name": "age", - "required": false, - "type": "number", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-a profile. You can load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Update a type-a profile. You can update any property present within the profile configuration. The updated profile will be printed so that you can review the result of the updates.", - "type": "command", - }, - Object { - "aliases": Array [ - "type-b", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-b", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "Type B profile for builder tests", - "name": "type-b-profile", - "options": Array [ - Object { - "absenceImplications": null, - "description": "The number of legs", - "implies": null, - "name": "legs", - "required": false, - "type": "number", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-b profile. You can load this profile by using the name on commands that support the \\"--type-b-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Update a type-b profile. You can update any property present within the profile configuration. The updated profile will be printed so that you can review the result of the updates.", - "type": "command", - }, - ], - "deprecatedReplacement": "The 'config set' command", - "description": "Update a {{type}} profile. You can update any property present within the profile configuration. The updated profile will be printed so that you can review the result of the updates.", - "name": "update", - "summary": "Update existing profiles", - "type": "group", - }, - Object { - "aliases": Array [ - "rm", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "Edit your Zowe V2 configuration - zowe.config.json", - "description": "Delete a type-a profile. You must specify a profile name to be deleted. To find a list of available profiles for deletion, issue the profiles list command. By default, you will be prompted to confirm the profile removal.", - "examples": Array [ - Object { - "description": "Delete a type-a profile named profilename", - "options": "profilename", - }, - ], - "name": "type-a-profile", - "options": Array [ - Object { - "aliases": Array [], - "description": "Force deletion of profile, and dependent profiles if specified. No prompt will be displayed before deletion occurs.", - "name": "force", - "required": false, - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-a profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Delete a type-a profile.", - "type": "command", - }, - Object { - "aliases": Array [ - "type-b", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-b", - }, - "deprecatedReplacement": "Edit your Zowe V2 configuration - zowe.config.json", - "description": "Delete a type-b profile. You must specify a profile name to be deleted. To find a list of available profiles for deletion, issue the profiles list command. By default, you will be prompted to confirm the profile removal.", - "examples": Array [ - Object { - "description": "Delete a type-b profile named profilename", - "options": "profilename", - }, - ], - "name": "type-b-profile", - "options": Array [ - Object { - "aliases": Array [], - "description": "Force deletion of profile, and dependent profiles if specified. No prompt will be displayed before deletion occurs.", - "name": "force", - "required": false, - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-b profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-b-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Delete a type-b profile.", - "type": "command", - }, - ], - "deprecatedReplacement": "Edit your Zowe V2 configuration zowe.config.json", - "description": "Delete existing profiles.", - "name": "delete", - "summary": "Delete existing profiles", - "type": "group", - }, - Object { - "aliases": Array [ - "ls", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config list' command", - "description": "Type A profile for builder tests", - "examples": Array [ - Object { - "description": "List profiles of type type-a", - "options": "", - }, - Object { - "description": "List profiles of type type-a and display their contents", - "options": "--sc", - }, - ], - "name": "type-a-profiles", - "options": Array [ - Object { - "aliases": Array [ - "sc", - ], - "description": "List type-a profiles and their contents. All profile details will be printed as part of command output.", - "name": "show-contents", - "required": false, - "type": "boolean", - }, - ], - "summary": "List profiles of the type type-a.", - "type": "command", - }, - Object { - "aliases": Array [ - "type-b", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-b", - }, - "deprecatedReplacement": "The 'config list' command", - "description": "Type B profile for builder tests", - "examples": Array [ - Object { - "description": "List profiles of type type-b", - "options": "", - }, - Object { - "description": "List profiles of type type-b and display their contents", - "options": "--sc", - }, - ], - "name": "type-b-profiles", - "options": Array [ - Object { - "aliases": Array [ - "sc", - ], - "description": "List type-b profiles and their contents. All profile details will be printed as part of command output.", - "name": "show-contents", - "required": false, - "type": "boolean", - }, - ], - "summary": "List profiles of the type type-b.", - "type": "command", - }, - ], - "deprecatedReplacement": "The 'config list' command", - "description": "List profiles of the type {{type}}.", - "name": "list", - "summary": "List existing profiles", - "type": "group", - }, - Object { - "aliases": Array [ - "set", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "The type-a set default-profiles command allows you to set the default profiles for this command group. When a type-a command is issued and no profile override options are specified, the default profiles for the command group are automatically loaded for the command based on the commands profile requirements.", - "examples": Array [ - Object { - "description": "Set the default profile for type type-a to the profile named 'profilename'", - "options": "profilename", - }, - ], - "name": "type-a-profile", - "options": Array [], - "positionals": Array [ - Object { - "description": "Specify a - profile for default usage within the type-a group. When you issue commands within the type-a group without a profile specified as part of the command, the default will be loaded instead.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Set the default profiles for the type-a group", - "type": "command", - }, - Object { - "aliases": Array [ - "type-b", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-b", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "The type-b set default-profiles command allows you to set the default profiles for this command group. When a type-b command is issued and no profile override options are specified, the default profiles for the command group are automatically loaded for the command based on the commands profile requirements.", - "examples": Array [ - Object { - "description": "Set the default profile for type type-b to the profile named 'profilename'", - "options": "profilename", - }, - ], - "name": "type-b-profile", - "options": Array [], - "positionals": Array [ - Object { - "description": "Specify a - profile for default usage within the type-b group. When you issue commands within the type-b group without a profile specified as part of the command, the default will be loaded instead.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Set the default profiles for the type-b group", - "type": "command", - }, - ], - "deprecatedReplacement": "The 'config set' command", - "description": "Set which profiles are loaded by default.", - "name": "set-default", - "summary": "Set which profiles are loaded by default", - "type": "group", - }, - Object { - "aliases": Array [ - "val", - ], - "children": Array [ - Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "Edit your Zowe V2 configuration - zowe.config.json", - "description": "Test the validity of a type-a profile.", - "name": "type-a-profile", - "options": Array [ - Object { - "aliases": Array [ - "plan", - "p", - ], - "description": "Instead of validating your profile, print out a table of the tasks used for validation. This will explain the different services and functionality that will be tested during profile validation.", - "name": "print-plan-only", - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-a profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": false, - "type": "string", - }, - ], - "summary": "Test the validity of a type-a profile.", - "type": "command", - }, - ], - "deprecatedReplacement": "Edit your Zowe V2 configuration zowe.config.json", - "description": "Test the validity of your profiles.", - "name": "validate", - "summary": "Test the validity of a profile", - "type": "group", - }, - ], - "deprecatedReplacement": "The 'config init' command", - "description": "Create and manage configuration profiles.", - "name": "profiles", - "summary": "Create and manage configuration profiles", - "type": "group", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesCreateCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesCreateCommandBuilder.unit.test.ts.snap deleted file mode 100644 index ef4241d63f..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesCreateCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,49 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Create Command Builder should provide a valid command definition for the profile create command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config init' command", - "description": "Type A profile for builder tests", - "name": "type-a-profile", - "options": Array [ - Object { - "description": "The age of the profile", - "name": "age", - "type": "number", - }, - Object { - "aliases": Array [ - "ow", - ], - "description": "Overwrite the type-a profile when a profile of the same name exists.", - "name": "overwrite", - "type": "boolean", - }, - Object { - "aliases": Array [ - "dd", - ], - "description": "Disable populating profile values of undefined properties with default values.", - "name": "disable-defaults", - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-a profile. You can load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Create a type-a profile", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesDeleteCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesDeleteCommandBuilder.unit.test.ts.snap deleted file mode 100644 index 6750e51a20..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesDeleteCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,42 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Delete Command Builder should provide a valid command definition for the profile delete command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "Edit your Zowe V2 configuration - zowe.config.json", - "description": "Delete a type-a profile. You must specify a profile name to be deleted. To find a list of available profiles for deletion, issue the profiles list command. By default, you will be prompted to confirm the profile removal.", - "examples": Array [ - Object { - "description": "Delete a type-a profile named profilename", - "options": "profilename", - }, - ], - "name": "type-a-profile", - "options": Array [ - Object { - "aliases": Array [], - "description": "Force deletion of profile, and dependent profiles if specified. No prompt will be displayed before deletion occurs.", - "name": "force", - "required": false, - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-a profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Delete a type-a profile.", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesListCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesListCommandBuilder.unit.test.ts.snap deleted file mode 100644 index 8dc551b1eb..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesListCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile List Command Builder should provide a valid command definition for the profile list command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config list' command", - "description": "Type A profile for builder tests", - "examples": Array [ - Object { - "description": "List profiles of type type-a", - "options": "", - }, - Object { - "description": "List profiles of type type-a and display their contents", - "options": "--sc", - }, - ], - "name": "type-a-profiles", - "options": Array [ - Object { - "aliases": Array [ - "sc", - ], - "description": "List type-a profiles and their contents. All profile details will be printed as part of command output.", - "name": "show-contents", - "required": false, - "type": "boolean", - }, - ], - "summary": "List profiles of the type type-a.", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesSetCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesSetCommandBuilder.unit.test.ts.snap deleted file mode 100644 index ac1a10f2a6..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesSetCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,34 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Set Command Builder should provide a valid command definition for the profile set command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "The type-a set default-profiles command allows you to set the default profiles for this command group. When a type-a command is issued and no profile override options are specified, the default profiles for the command group are automatically loaded for the command based on the commands profile requirements.", - "examples": Array [ - Object { - "description": "Set the default profile for type type-a to the profile named 'profilename'", - "options": "profilename", - }, - ], - "name": "type-a-profile", - "options": Array [], - "positionals": Array [ - Object { - "description": "Specify a - profile for default usage within the type-a group. When you issue commands within the type-a group without a profile specified as part of the command, the default will be loaded instead.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Set the default profiles for the type-a group", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesShowDependenciesCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesShowDependenciesCommandBuilder.unit.test.ts.snap deleted file mode 100644 index c43a6c28e8..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesShowDependenciesCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,26 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Show Dependencies Command Builder should provide a valid command definition for the profile show dependencies command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "description": "Type A profile for builder tests", - "name": "type-a-profile", - "options": Array [], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-a profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "View all profiles which may be used within a selected group.", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesUpdateCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesUpdateCommandBuilder.unit.test.ts.snap deleted file mode 100644 index d432d7c49e..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesUpdateCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Update Command Builder should provide a valid command definition for the profile update command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "The 'config set' command", - "description": "Type A profile for builder tests", - "name": "type-a-profile", - "options": Array [ - Object { - "absenceImplications": null, - "description": "The age of the profile", - "implies": null, - "name": "age", - "required": false, - "type": "number", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the new type-a profile. You can load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": true, - "type": "string", - }, - ], - "summary": "Update a type-a profile. You can update any property present within the profile configuration. The updated profile will be printed so that you can review the result of the updates.", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesValidateCommandBuilder.unit.test.ts.snap b/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesValidateCommandBuilder.unit.test.ts.snap deleted file mode 100644 index d40611823b..0000000000 --- a/packages/imperative/src/cmd/__tests__/profiles/builders/__snapshots__/ProfilesValidateCommandBuilder.unit.test.ts.snap +++ /dev/null @@ -1,38 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Profile Validate Command Builder should provide a valid command definition for the profile validate command based on our test profile type 1`] = ` -Object { - "aliases": Array [ - "type-a", - ], - "children": Array [], - "customize": Object { - "profileTypeIdentifier": "type-a", - }, - "deprecatedReplacement": "Edit your Zowe V2 configuration - zowe.config.json", - "description": "Test the validity of a type-a profile.", - "name": "type-a-profile", - "options": Array [ - Object { - "aliases": Array [ - "plan", - "p", - ], - "description": "Instead of validating your profile, print out a table of the tasks used for validation. This will explain the different services and functionality that will be tested during profile validation.", - "name": "print-plan-only", - "type": "boolean", - }, - ], - "positionals": Array [ - Object { - "description": "Specifies the name of the type-a profile to be deleted. You can also load this profile by using the name on commands that support the \\"--type-a-profile\\" option.", - "name": "profileName", - "required": false, - "type": "string", - }, - ], - "summary": "Test the validity of a type-a profile.", - "type": "command", -} -`; diff --git a/packages/imperative/src/cmd/__tests__/yargs/YargsConfigurer.unit.test.ts b/packages/imperative/src/cmd/__tests__/yargs/YargsConfigurer.unit.test.ts index 6c3b0c7049..a8fdb33957 100644 --- a/packages/imperative/src/cmd/__tests__/yargs/YargsConfigurer.unit.test.ts +++ b/packages/imperative/src/cmd/__tests__/yargs/YargsConfigurer.unit.test.ts @@ -19,7 +19,7 @@ describe("YargsConfigurer tests", () => { it("should build a failure message", () => { const config = new YargsConfigurer({ name: "any", description: "any", type: "command", children: []}, - undefined, undefined, undefined, undefined, undefined, "fake", "fake", "ZOWE", "fake"); + undefined, undefined as any, undefined as any, undefined as any, "fake", "fake", "ZOWE", "fake"); ImperativeConfig.instance.commandLine = "some-command"; @@ -30,13 +30,13 @@ describe("YargsConfigurer tests", () => { it("should get response format from --response-format-json option", () => { const mockedYargs = require("yargs"); - const invokeSpy = jest.spyOn(CommandProcessor.prototype, "invoke").mockResolvedValue(undefined); + const invokeSpy = jest.spyOn(CommandProcessor.prototype, "invoke").mockResolvedValue(undefined as any); jest.spyOn(mockedYargs, "command").mockImplementation((obj: any) => { obj.handler({ _: ["abc"], [Constants.JSON_OPTION]: true }); }); const config = new YargsConfigurer({ name: "any", description: "any", type: "command", children: []}, - mockedYargs, undefined, undefined, { getHelpGenerator: jest.fn() }, undefined, "fake", "fake", "ZOWE", "fake"); + mockedYargs, undefined as any, { getHelpGenerator: jest.fn() }, undefined as any, "fake", "fake", "ZOWE", "fake"); config.configure(); expect(invokeSpy).toHaveBeenCalledTimes(1); @@ -52,7 +52,7 @@ describe("YargsConfigurer tests", () => { */ const configureYargsTwice = () => { const config = new YargsConfigurer({ name: "any", description: "any", type: "command", children: []}, - mockedYargs, undefined, undefined, { getHelpGenerator: jest.fn() }, undefined, "fake", "fake", "ZOWE", "fake"); + mockedYargs, undefined as any, { getHelpGenerator: jest.fn() }, undefined as any, "fake", "fake", "ZOWE", "fake"); buildFailedCmdDefSpy = jest.spyOn(config as any, "buildFailedCommandDefinition"); ImperativeConfig.instance.commandLine = "first-command"; diff --git a/packages/imperative/src/cmd/src/CommandProcessor.ts b/packages/imperative/src/cmd/src/CommandProcessor.ts index c546049eb8..2221ce2910 100644 --- a/packages/imperative/src/cmd/src/CommandProcessor.ts +++ b/packages/imperative/src/cmd/src/CommandProcessor.ts @@ -17,15 +17,14 @@ import { ICommandHandler } from "./doc/handler/ICommandHandler"; import { couldNotInstantiateCommandHandler, unexpectedCommandError } from "../../messages"; import { SharedOptions } from "./utils/SharedOptions"; import { IImperativeError, ImperativeError } from "../../error"; -import { IProfileManagerFactory, ProfileUtils } from "../../profiles"; +import { ProfileUtils } from "../../profiles"; import { SyntaxValidator } from "./syntax/SyntaxValidator"; import { CommandProfileLoader } from "./profiles/CommandProfileLoader"; -import { ICommandProfileTypeConfiguration } from "./doc/profiles/definition/ICommandProfileTypeConfiguration"; import { IHelpGenerator } from "./help/doc/IHelpGenerator"; import { ICommandPrepared } from "./doc/response/response/ICommandPrepared"; import { CommandResponse } from "./response/CommandResponse"; import { ICommandResponse } from "./doc/response/response/ICommandResponse"; -import { Logger, LoggerUtils } from "../../logger"; +import { Logger } from "../../logger"; import { IInvokeCommandParms } from "./doc/parms/IInvokeCommandParms"; import { ICommandProcessorParms } from "./doc/processor/ICommandProcessorParms"; import { ImperativeExpect } from "../../expect"; @@ -62,13 +61,6 @@ interface IResolvedArgsResponse { */ commandValues?: ICommandArguments; - /** - * Whether we're using old profiles or config - * @type {(`v1` | `v2`)} - * @memberof IResolvedArgsResponse - */ - profileVersion?: `v1` | `v2`; - /** * The profiles that are required * @type {string[]} @@ -163,13 +155,6 @@ export class CommandProcessor { * @memberof CommandProcessor */ private mHelpGenerator: IHelpGenerator; - /** - * The profile manager to use when loading profiles for commands - * @private - * @type {IProfileManagerFactory} - * @memberof CommandProcessor - */ - private mProfileManagerFactory: IProfileManagerFactory; /** * Imperative Logger instance for logging from the command processor. * @private @@ -204,8 +189,6 @@ export class CommandProcessor { this.mFullDefinition = (params.fullDefinition == null) ? this.mDefinition : params.fullDefinition; this.mHelpGenerator = params.helpGenerator; ImperativeExpect.toNotBeNullOrUndefined(this.mHelpGenerator, `${CommandProcessor.ERROR_TAG} No help generator supplied.`); - this.mProfileManagerFactory = params.profileManagerFactory; - ImperativeExpect.toNotBeNullOrUndefined(this.mProfileManagerFactory, `${CommandProcessor.ERROR_TAG} No profile manager factory supplied.`); if (this.mDefinition.type === "command" && this.mDefinition.chainedHandlers == null) { ImperativeExpect.keysToBeDefinedAndNonBlank(this.mDefinition, ["handler"], `${CommandProcessor.ERROR_TAG} ` + `The definition supplied is of type "command", ` + @@ -283,16 +266,6 @@ export class CommandProcessor { return this.mConfig; } - /** - * Accessor for the profile manager factory in use for this command processor. - * @readonly - * @type {IProfileManagerFactory} - * @memberof CommandProcessor - */ - get profileFactory(): IProfileManagerFactory { - return this.mProfileManagerFactory; - } - /** * Obtain a copy of the command definition * @return {ICommandDefinition}: The Zowe Commands definition document. @@ -787,21 +760,12 @@ export class CommandProcessor { showSecure = true; } - // if config exists and a layer exists, use config - let useConfig = false; - this.mConfig?.layers.forEach((layer) => { - if (layer.exists) { - useConfig = true; - } - }); - /** * Begin building response object */ const showInputsOnly: IResolvedArgsResponse = { - commandValues: {} as ICommandArguments, - profileVersion: useConfig ? `v2` : `v1`, + commandValues: {} as ICommandArguments }; /** @@ -814,28 +778,20 @@ export class CommandProcessor { const configSecureProps: string[] = []; /** - * If using config, then we need to get the secure properties from the config + * Need to get the secure properties from the config */ - if (useConfig) { + const combinedProfiles = [ ...showInputsOnly.requiredProfiles ?? [], ...showInputsOnly.optionalProfiles ?? [] ]; + combinedProfiles.forEach((profile) => { + const name = ConfigUtils.getActiveProfileName(profile, commandParameters.arguments); // get profile name + const props = this.mConfig.api.secure.securePropsForProfile(name); // get secure props + configSecureProps.push(...props); // add to list + }); - const combinedProfiles = [ ...showInputsOnly.requiredProfiles ?? [], ...showInputsOnly.optionalProfiles ?? [] ]; - combinedProfiles.forEach((profile) => { - const name = ConfigUtils.getActiveProfileName(profile, commandParameters.arguments); // get profile name - const props = this.mConfig.api.secure.securePropsForProfile(name); // get secure props - configSecureProps.push(...props); // add to list - }); - } /** - * Determine if Zowe V2 Config is in effect. If it is, then we will construct - * a Set of secure fields from its API. If it is not, then we will construct - * a Set of secure fields from the `ConnectionPropsForSessCfg` defaults. + * Construct a Set of secure fields from Zowe Team Config API. */ - const secureInputs: Set = - useConfig ? - new Set([...configSecureProps]) : - new Set([...LoggerUtils.CENSORED_OPTIONS, ...LoggerUtils.SECURE_PROMPT_OPTIONS]); - + const secureInputs: Set = new Set([...configSecureProps]); let censored = false; /** @@ -858,15 +814,11 @@ export class CommandProcessor { /** * Add profile location info */ - if (useConfig) { - this.mConfig.mLayers.forEach((layer) => { - if (layer.exists) { - showInputsOnly.locations.push(layer.path); - } - }); - } else { - showInputsOnly.locations.push(nodePath.normalize(ImperativeConfig.instance.cliHome)); - } + this.mConfig?.mLayers?.forEach((layer) => { + if (layer.exists) { + showInputsOnly.locations.push(layer.path); + } + }); /** * Show warning if we censored output and we were not instructed to show secure values @@ -1023,8 +975,7 @@ export class CommandProcessor { `Profile definitions: ${inspect(this.definition.profile, { depth: null })}`); const profiles = await CommandProfileLoader.loader({ - commandDefinition: this.definition, - profileManagerFactory: this.profileFactory + commandDefinition: this.definition }).loadProfiles(args); this.log.trace(`Profiles loaded for "${this.definition.name}" command:\n${inspect(profiles, { depth: null })}`); diff --git a/packages/imperative/src/cmd/src/doc/handler/IHandlerParameters.ts b/packages/imperative/src/cmd/src/doc/handler/IHandlerParameters.ts index b4d56d733d..247b68bcde 100644 --- a/packages/imperative/src/cmd/src/doc/handler/IHandlerParameters.ts +++ b/packages/imperative/src/cmd/src/doc/handler/IHandlerParameters.ts @@ -56,7 +56,6 @@ export interface IHandlerParameters { * The set of profiles loaded for this command handler - the map is built with the key being the type and it * returns the set of profiles loaded of that type. Multiple profiles can be loaded of the same type - depending * on the request and the 0th entry is the first loaded. - * @deprecated This API only loads v1 profiles. To load v2 profiles, use `ImperativeConfig.instance.config.api.profiles`. * @type {Map} * @memberof IHandlerParameters */ diff --git a/packages/imperative/src/cmd/src/doc/processor/ICommandProcessorParms.ts b/packages/imperative/src/cmd/src/doc/processor/ICommandProcessorParms.ts index 82ffd3fd02..0f94aec062 100644 --- a/packages/imperative/src/cmd/src/doc/processor/ICommandProcessorParms.ts +++ b/packages/imperative/src/cmd/src/doc/processor/ICommandProcessorParms.ts @@ -11,8 +11,6 @@ import { ICommandDefinition } from "../ICommandDefinition"; import { IHelpGenerator } from "../../help/doc/IHelpGenerator"; -import { IProfileManagerFactory } from "../../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../../../src/doc/profiles/definition/ICommandProfileTypeConfiguration"; import { Config } from "../../../../config"; import { IDaemonContext } from "../../../../imperative/src/doc/IDaemonContext"; @@ -36,13 +34,6 @@ export interface ICommandProcessorParms { * @memberof ICommandProcessorParms */ helpGenerator: IHelpGenerator; - /** - * The profile manager factory allows the command processor to obtain an instance of the profile manager for - * the command being issued. - * @type {IProfileManagerFactory} - * @memberof ICommandProcessorParms - */ - profileManagerFactory: IProfileManagerFactory; /** * The root command name for the CLI - used in help generation, etc. * @type {string} diff --git a/packages/imperative/src/cmd/src/doc/profiles/definition/ICommandProfileTypeConfiguration.ts b/packages/imperative/src/cmd/src/doc/profiles/definition/ICommandProfileTypeConfiguration.ts index a2e86a1aa8..ad77a27e7d 100644 --- a/packages/imperative/src/cmd/src/doc/profiles/definition/ICommandProfileTypeConfiguration.ts +++ b/packages/imperative/src/cmd/src/doc/profiles/definition/ICommandProfileTypeConfiguration.ts @@ -11,7 +11,6 @@ import { ICommandProfileSchema } from "./ICommandProfileSchema"; import { IProfileTypeConfiguration } from "../../../../.."; -import { ICommandExampleDefinition } from "../../ICommandExampleDefinition"; import { ICommandProfileAuthConfig } from "./ICommandProfileAuthConfig"; /** @@ -22,56 +21,6 @@ import { ICommandProfileAuthConfig } from "./ICommandProfileAuthConfig"; * @extends {IProfileTypeConfiguration} */ export interface ICommandProfileTypeConfiguration extends IProfileTypeConfiguration { - /** - * A handler module which Imperative will require(). - * The module's default export should be a handler that calls - * appendResponseObject on the provided commandParameters.response - * You do NOT have to implement writing the profile to disk -- you only have to produce - * the final profile object that you would like to be written. - * - * - * This is only required if finished profile can't be created directly from the arguments, e.g. - * if you have --user and --password and need to always transform it into a basic auth - * - * - * If omitted, Imperative will just write all fields present from the schema into the profile - * without requiring a module - * - * @type {string} - * @memberof IProfileTypeConfiguration - */ - createProfileFromArgumentsHandler?: string; - /** - * The module's default export should be a handler that calls appendResponseObject on the provided - * commandParameters.response You do NOT have to implement writing the profile to disk -- you only have to produce - * the final profile object that you would like to be written. - * - * This is only required if finished updated profile can't be created directly from the arguments, e.g. - * if certain fields that the user might specify mean that other fields should be deleted or updated. - * - * If omitted, Imperative will load the old profile, overwrite any fields specified by the user, - * and write the updated profile to disk. - * - * @type {string} - * @memberof IProfileTypeConfiguration - */ - updateProfileFromArgumentsHandler?: string; - /** - * Examples to be displayed in the help text for the auto generated create profile command. - * - * @type {ICommandExampleDefinition[]} - * @memberof IProfileTypeConfiguration - */ - createProfileExamples?: ICommandExampleDefinition[]; - - /** - * Examples to be displayed in the help text for the auto generated update profile command. - * - * @type {ICommandExampleDefinition[]} - * @memberof IProfileTypeConfiguration - */ - updateProfileExamples?: ICommandExampleDefinition[]; - /** * The JSON schema document. The schema document provides a way to enforce the contents of a profile. The schema * conforms exactly to the JSON schema specification. You must supply all properties you would like validated diff --git a/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadAllProfiles.ts b/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadAllProfiles.ts deleted file mode 100644 index bf6cd2f640..0000000000 --- a/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadAllProfiles.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ILoadAllProfiles } from "../../../../../profiles"; - -/** - * Optional parameters to profile manager load all profiles - * @export - * @interface ICliLoadAllProfiles - * @extends ILoadAllProfiles - */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICliLoadAllProfiles extends ILoadAllProfiles {} diff --git a/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadProfile.ts b/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadProfile.ts deleted file mode 100644 index ac1a6ba0e9..0000000000 --- a/packages/imperative/src/cmd/src/doc/profiles/parms/ICliLoadProfile.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ILoadProfile } from "../../../../../profiles"; - -/** - * Profile Manager "loadProfile" input parameters. Indicates which profile to load (named or default) and if - * not finding the profile should be considered and error, etc. - * @export - * @interface ICliLoadProfile - * @extends ILoadProfile - */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICliLoadProfile extends ILoadProfile {} diff --git a/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandLoadProfile.ts b/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandLoadProfile.ts deleted file mode 100644 index dffa08aff2..0000000000 --- a/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandLoadProfile.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * Command profile loader internal parameters. Indicates the profile to be loaded (by name) and - * other options/control parameters. - * @export - * @interface ICommandLoadProfile - */ -export interface ICommandLoadProfile { - /** - * The type of the profile to load. - * @type {string} - * @memberof ICommandLoadProfile - */ - type: string; - /** - * The name of the profile to load for the type specified. - * @type {string} - * @memberof ICommandLoadProfile - */ - name: string; - /** - * Indicates that the user specifically named this profile to be loaded (not a default, etc.) - * @type {boolean} - * @memberof ICommandLoadProfile - */ - userSpecified: boolean; - /** - * Load the default profile for the group. If this option is specified, name is ignored. - * @type {boolean} - * @memberof ICommandLoadProfile - */ - loadDefault: boolean; - /** - * Indicates that a failure to load this profile is not a problem. - * @type {boolean} - * @memberof ICommandLoadProfile - */ - optional: boolean; -} diff --git a/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandProfileLoaderParms.ts b/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandProfileLoaderParms.ts index b0a22d2dad..35837a8abb 100644 --- a/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandProfileLoaderParms.ts +++ b/packages/imperative/src/cmd/src/doc/profiles/parms/ICommandProfileLoaderParms.ts @@ -9,10 +9,8 @@ * */ -import { IProfileManagerFactory } from "../../../../../profiles"; import { Logger } from "../../../../../logger"; import { ICommandDefinition } from "../../ICommandDefinition"; -import { ICommandProfileTypeConfiguration } from "../definition/ICommandProfileTypeConfiguration"; /** * Control parameters for the command profile loader. * @export @@ -25,13 +23,6 @@ export interface ICommandProfileLoaderParms { * @memberof ICommandProfileLoaderParms */ commandDefinition: ICommandDefinition; - /** - * The profile Manager factory to create profile manager instances depending on the profile types required - * by the command. - * @type {IProfileManagerFactory} - * @memberof ICommandProfileLoaderParms - */ - profileManagerFactory: IProfileManagerFactory; /** * Optional logger instance - if not supplied, then Logger.getImperativeLogger() is used. * @type {Logger} diff --git a/packages/imperative/src/cmd/src/profiles/CliProfileManager.ts b/packages/imperative/src/cmd/src/profiles/CliProfileManager.ts index a4aa983665..86ec374457 100644 --- a/packages/imperative/src/cmd/src/profiles/CliProfileManager.ts +++ b/packages/imperative/src/cmd/src/profiles/CliProfileManager.ts @@ -9,686 +9,181 @@ * */ -import { - BasicProfileManager, - IProfile, - IProfileManager, - IProfileSaved, - IProfileUpdated, - IProfileValidated, - ISaveProfileFromCliArgs, - IUpdateProfileFromCliArgs, - IValidateProfileForCLI, - ProfilesConstants, - ProfileUtils -} from "../../../profiles"; -import { inspect } from "util"; +import { ImperativeExpect } from "../../../expect"; +import { inspect, isNullOrUndefined } from "util"; +import { Logger } from "../../../logger"; import { ImperativeError } from "../../../error"; -import { Arguments } from "yargs"; -import { CommandResponse } from "../response/CommandResponse"; -import { ICommandHandlerRequire } from "../doc/handler/ICommandHandlerRequire"; -import { ICommandHandler } from "../../src/doc/handler/ICommandHandler"; import { ICommandProfileTypeConfiguration } from "../doc/profiles/definition/ICommandProfileTypeConfiguration"; -import { CommandProfiles } from "./CommandProfiles"; -import { ICommandProfileProperty } from "../doc/profiles/definition/ICommandProfileProperty"; -import { CredentialManagerFactory } from "../../../security"; -import { IDeleteProfile, IProfileDeleted, IProfileLoaded } from "../../../profiles/src/doc"; -import { SecureOperationFunction } from "../types/SecureOperationFunction"; -import { ICliLoadProfile } from "../doc/profiles/parms/ICliLoadProfile"; -import { ICliLoadAllProfiles } from "../doc/profiles/parms/ICliLoadAllProfiles"; -import { CliUtils } from "../../../utilities/src/CliUtils"; +import { + IProfileManager, + IProfileSchema, +} from "../../../profiles/src/doc"; /** - * A profile management API compatible with transforming command line arguments into - * profiles + * The CLI profile manager contains methods to manage Zowe profiles. Profiles + * are user configuration documents intended to be used on commands, as a convenience, to supply a slew of additional + * input and configuration (normally more than would be feasible as command arguments). See the "IProfile" interface + * for a detailed description of profiles, their use case, and examples. + * + * The Profile Manager no longer reads V1 profile from disk. It only processes profile information from a + * command's definition. The Config class now handles reading profiles from disk stored in a zowe.config.json file. */ -export class CliProfileManager extends BasicProfileManager { - +export class CliProfileManager { /** - * NOTE: This is just a copy of BasicProfileManager.loadAll - * REASON: We needed the Abstract profile manager to call the CLI profile manager to handle loading of secure properties - * Loads all profiles from every type. Profile types are determined by reading all directories within the - * profile root directory. - * @returns {Promise} - The list of all profiles for every type + * Parameters passed on the constructor (normally used to create additional instances of profile manager objects) + * @private + * @type {IProfileManager} + * @memberof CliProfileManager */ - public async loadAll(params?: ICliLoadAllProfiles): Promise { - this.log.trace(`Loading all profiles for type "${this.profileType}"...`); - // Load all the other profiles for other types - const loadAllProfiles: any[] = []; - - // Load only the profiles for the type if requested - if (params != null && params.typeOnly) { - const names: string[] = this.getAllProfileNames(); - for (const name of names) { - loadAllProfiles.push(this.load({ - name, - failNotFound: true, - loadDependencies: false, - noSecure: params.noSecure - })); - } - } else { - - // Otherwise, load all profiles of all types - for (const typeConfig of this.profileTypeConfigurations) { - const typeProfileManager = new CliProfileManager({ - profileRootDirectory: this.profileRootDirectory, - typeConfigurations: this.profileTypeConfigurations, - type: typeConfig.type, - logger: this.log, - loadCounter: this.loadCounter - }); - - // Get all the profile names for the type and attempt to load every one - const names: string[] = typeProfileManager.getAllProfileNames(); - for (const name of names) { - this.log.debug(`Loading profile "${name}" of type "${typeConfig.type}".`); - loadAllProfiles.push(typeProfileManager.load({ - name, - failNotFound: true, - loadDependencies: false, - noSecure: (params != null) ? params.noSecure : undefined - })); - } - } - } - - // Construct the full list for return - let allProfiles: IProfileLoaded[] = []; - try { - this.log.trace(`Awaiting all loads...`); - const theirProfiles = await Promise.all(loadAllProfiles); - for (const theirs of theirProfiles) { - allProfiles = allProfiles.concat(theirs); - } - this.log.trace(`All loads complete.`); - } catch (e) { - this.log.error(e.message); - throw new ImperativeError({msg: e.message, additionalDetails: e.additionalDetails, causeErrors: e}); - } - - return allProfiles; - } + private mConstructorParms: IProfileManager; /** - * Overridden saveProfile functionality. - * If CLI args are provided, profile fields are built from the args. - * Otherwise BaseProfileManager functionality is used. - * @param {ISaveProfileFromCliArgs} parms - parameters for the save, potentially including CLI args - * @returns {Promise} - promise which fulfills with the save results + * The full set of profile type configurations. The manager needs to ensure that A) the profile type configuration + * is among the set (because it contains schema and dependency specifications) and B) That other type configurations + * are available. + * @private + * @type {ICommandProfileTypeConfiguration[]} + * @memberof CliProfileManager */ - protected async saveProfile(parms: ISaveProfileFromCliArgs): Promise { - // If the arguments are present, build the new profile from the arguments - // Otherwise, just save the profile passed. - this.log.trace("Cli save profile entered"); - const validationParms: IValidateProfileForCLI = JSON.parse(JSON.stringify(parms)); - validationParms.readyForValidation = true; - - if (parms.args != null) { - this.log.trace(`Arguments supplied, constructing profile from arguments:\n${inspect(parms.args, {depth: null})}`); - parms.profile = await this.createProfileFromCommandArguments(parms.args, parms.profile); - - validationParms.profile = parms.profile; - delete parms.args; - this.log.debug(`Validating profile build (name: ${parms.name}).`); - await this.validate(validationParms); // validate now that the profile has been built - } else { - // profile should already be ready - this.log.trace("No arguments specified, performing the basic validation (schema, etc.)."); - await this.validate(validationParms); - } - parms.profile = await this.processSecureProperties(parms.name, parms.profile); - return super.saveProfile(parms); - } + private mProfileTypeConfigurations: ICommandProfileTypeConfiguration[]; /** - * Overridden updateProfile functionality - * If CLI args are provided, profile fields are built from the arguments. Otherwise - * the BaseProfileManager update functionality is used - * - * @param {IUpdateProfileFromCliArgs} parms - parameters, potentially including CLI args - * @returns {Promise} - promise which contains the updated profile, path, and message - * when fulfilled + * The profile "type" for this manager - indicating the profile/schema that this manager is working directly with. + * @private + * @type {string} + * @memberof CliProfileManager */ - protected async updateProfile(parms: IUpdateProfileFromCliArgs): Promise { - // If there are arguments present, then it is assumed that we want to update from the args, - // otherwise we will invoke the default updateProfile which assumes that the profile update - // has already been constructed and just needs to be saved. - // When updating from the args, we do not need to run validation twice when saving the profile - let updated: any; - if (parms.args != null) { - const newManagerParams: IProfileManager = JSON.parse(JSON.stringify(this.managerParameters)); - newManagerParams.loadCounter = this.loadCounter; - newManagerParams.logger = this.log; - const loadedProfile = await new CliProfileManager(newManagerParams).loadProfile({name: parms.name}); - updated = await this.updateProfileFromCliArgs(parms, loadedProfile.profile, - (parms.profile == null) ? {} : parms.profile); - delete parms.args; - this.log.debug("Profile \"%s\" of type \"%s\" has been updated from CLI arguments. " + - "Validating the structure of the profile.", parms.name, this.profileType); - } else { - updated = await super.updateProfile(parms); - this.log.debug("No CLI args were provided. Used the BasicProfileManager update API"); - - const validationParms: IValidateProfileForCLI = JSON.parse(JSON.stringify(parms)); - validationParms.readyForValidation = true; - validationParms.profile = updated.profile; - await this.validateProfile(validationParms); - } - - return updated; - } + private mProfileType: string; /** - * Overridden loadProfile functionality - * After the BasicProfileManager loads the profile, we process the secured properties for the CLi to use - * - * @param {ICliLoadProfile} parms - Load control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) + * Product display name of the CLI. + * @private + * @type {string} + * @memberof CliProfileManager */ - protected async loadProfile(parms: ICliLoadProfile): Promise { - const loadedProfile = await super.loadProfile(parms); - const profile = loadedProfile.profile; - - // If noSecure is specified, skip secure loading - let securelyLoadValue: SecureOperationFunction; - if (!parms.noSecure && CredentialManagerFactory.initialized) { - /** - * Securely load a property associated with a given profile - * @param {string} propertyNamePath - The path to the property - * @return {Promise} - */ - securelyLoadValue = async (propertyNamePath: string, _: any, optional?: boolean): Promise => { - let ret; - try { - this.log.debug( - `Loading secured field with key ${propertyNamePath} for profile` + - ` ("${parms.name}" of type "${this.profileType}").` - ); - // Use the Credential Manager to store the credentials - ret = await CredentialManagerFactory.manager.load( - ProfileUtils.getProfilePropertyKey(this.profileType, parms.name, propertyNamePath), - optional - ); - } catch (err) { - this.log.error( - `Unable to load secure field "${propertyNamePath}" ` + - `associated with profile "${parms.name}" of type "${this.profileType}".` - ); - - let additionalDetails: string = err.message + (err.additionalDetails ? `\n${err.additionalDetails}` : ""); - additionalDetails = this.addProfileInstruction(additionalDetails); - - this.log.error(`Error: ${additionalDetails}`); - if (err.causeErrors != null) { - this.log.error("Cause errors: " + inspect(err.causeErrors)); - } - throw new ImperativeError({ - msg: `Unable to load the secure field "${propertyNamePath}" associated with ` + - `the profile "${parms.name}" of type "${this.profileType}".`, - additionalDetails, - causeErrors: err - }); - } - - return (ret != null) ? JSON.parse(ret) : undefined; // Parse it after loading it. We stringify-ed before saving it - }; - } - - if (profile != null) { - for (const prop of Object.keys(this.profileTypeConfiguration.schema.properties)) { - profile[prop] = await this.findOptions(this.profileTypeConfiguration.schema.properties[prop], prop, profile[prop], securelyLoadValue); - } - } - - // Return the loaded profile - loadedProfile.profile = profile || {}; - return loadedProfile; - } + private mProductDisplayName: string; /** - * Overridden loadProfile functionality - * Before the BasicProfileManager deletes the profile, we remove the secure properties associated with the profile - * - * @param {IDeleteProfile} parms - Delete control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) + * Logger instance - must be log4js compatible. Can be the Imperative logger (normally), but is required for + * profile manager operation. + * @private + * @type {Logger} + * @memberof CliProfileManager */ - protected async deleteProfile(parms: IDeleteProfile): Promise { - - // If the credential manager is null, we are using plain text - let deleteSecureProperty: SecureOperationFunction; - if (CredentialManagerFactory.initialized) { - /** - * Delete a secure property associated with a given profile - * @param {string} propertyNamePath - The path to the property - * @return {Promise} - */ - deleteSecureProperty = async (propertyNamePath: string): Promise => { - try { - this.log - .debug(`Deleting secured field with key ${propertyNamePath} for profile ("${parms.name}" of type "${this.profileType}").`); - // Use the Credential Manager to store the credentials - await CredentialManagerFactory.manager.delete( - ProfileUtils.getProfilePropertyKey(this.profileType, parms.name, propertyNamePath) - ); - } catch (err) { - this.log.error(`Unable to delete secure field "${propertyNamePath}" ` + - `associated with profile "${parms.name}" of type "${this.profileType}".`); - - let additionalDetails: string = err.message + (err.additionalDetails ? `\n${err.additionalDetails}` : ""); - additionalDetails = this.addProfileInstruction(additionalDetails); - this.log.error(`Error: ${additionalDetails}`); - - throw new ImperativeError({ - msg: `Unable to delete the secure field "${propertyNamePath}" associated with ` + - `the profile "${parms.name}" of type "${this.profileType}".`, - additionalDetails, - causeErrors: err - }); - } - }; - } - - for (const prop of Object.keys(this.profileTypeConfiguration.schema.properties)) { - await this.findOptions(this.profileTypeConfiguration.schema.properties[prop], prop, null, deleteSecureProperty); - } - - return super.deleteProfile(parms); - } + private mLogger: Logger = Logger.getImperativeLogger(); /** - * Validate a profile's structure, skipping the validation if we haven't built the - * profile's fields from the CLI arguments yet. - * @param {IValidateProfileForCLI} parms - validate profile parameters. if these don't - * have readyForValidation = true, validation is - * skipped - * @returns {Promise} - */ - protected async validateProfile(parms: IValidateProfileForCLI): Promise { - if (parms.readyForValidation) { - this.log.debug(`Invoking the basic profile manager validate for profile: "${parms.name}"`); - return super.validateProfile(parms); - } else { - this.log.trace(`Skipping the validate for profile (as it's being built): "${parms.name}"`); - return {message: "Skipping validation until profile is built"}; - } - } - - /** - * After the DefaultCredentialManager reports an error resolution of recreating - * a credential, add instruction to recreate the profile. - * - * @param {String} errDetails - The additional details of an error thrown - * by DefaultCredentialManager. - * - * @returns {string} An error details string that contains an instruction to - * recreate the profile (when appropriate). - */ - private addProfileInstruction(errDetails: string): string { - const recreateCredText: string = "Recreate the credentials in the vault"; - const recreateProfileText: string = - " To recreate credentials, issue a 'profiles create' sub-command with the --ow flag.\n"; - if (errDetails.includes(recreateCredText)) { - errDetails += recreateProfileText; - } else { - const additionalDetails = CredentialManagerFactory.manager.secureErrorDetails(); - if (additionalDetails != null) { - errDetails += "\n\n" + additionalDetails; - } - } - return errDetails; - } - - /** - * Helper routine to find nested properties - * Inspired by the inner function of insertCliArgumentsIntoProfile + * Creates an instance of ProfileManager - Performs basic parameter validation. + * It accepts the type definitions passed on the constructor parameters. * - * @param {ICommandProfileProperty} prop - profile property - * @param {string} propNamePath - Dot notation path of a property (e.g. my.nested.property) - * @param {*} propValue - Current value of the property while traversing down the object tree - * @param {SecureOperationFunction} secureOp - Function to be executed if we are supposed to process secure properties - * @returns {Promise} Processed version of a property + * @param {IProfileManager} parms - See the interface for details. + * @memberof ProfileManager */ - private async findOptions(prop: ICommandProfileProperty, propNamePath: string, propValue: any, secureOp?: SecureOperationFunction): Promise { - if (prop.optionDefinition != null) { - // once we reach a property with an option definition, - // we now have the complete path to the property - // so we will set the value on the property from the profile - const optionName = prop.optionDefinition.name; - this.log.debug("Setting profile field %s from command line option %s", propNamePath, optionName); - if (secureOp && prop.secure) { - this.log.debug("Performing secure operation on property %s", propNamePath); - return secureOp(propNamePath, propValue, !prop.optionDefinition.required); - } - return Promise.resolve(propValue); + constructor(parms: IProfileManager) { + ImperativeExpect.toNotBeNullOrUndefined(parms, "Profile Manager input parms not supplied."); + ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["type"], + "No profile type supplied on the profile manager parameters."); + this.mLogger = isNullOrUndefined(parms.logger) ? this.mLogger : parms.logger; + this.mProfileType = parms.type; + this.mProfileTypeConfigurations = parms.typeConfigurations; + this.mProductDisplayName = parms.productDisplayName; + if (isNullOrUndefined(this.profileTypeConfigurations) || this.profileTypeConfigurations.length === 0) { + throw new ImperativeError({ + msg: "V1 profiles are no longer read from disk. " + + "You can supply the profile type configurations to the profile manager constructor." + }); } - if (prop.properties != null) { - if (secureOp && prop.secure) { - if (!propValue || Object.keys(propValue).length === 0) { // prevents from performing operations on empty objects - return Promise.resolve(null); - } - - this.log.debug("Performing secure operation on property %s", propNamePath); - return secureOp(propNamePath, propValue); - } - const tempProperties: any = {}; - for (const childPropertyName of Object.keys(prop.properties)) { - tempProperties[childPropertyName] = - await this.findOptions( - prop.properties[childPropertyName], - propNamePath + "." + childPropertyName, - ((propValue != null) && (propValue[childPropertyName] != null)) ? - JSON.parse(JSON.stringify(propValue[childPropertyName])) : null, - secureOp - ); - } - return Promise.resolve(tempProperties); + this.mConstructorParms = parms; + ImperativeExpect.arrayToContain(this.mProfileTypeConfigurations, (entry) => { + return entry.type === this.mProfileType; + }, `Could not locate the profile type configuration for "${this.profileType}" within the input configuration list passed.` + + `\n${inspect(this.profileTypeConfigurations, { depth: null })}`); + for (const config of this.profileTypeConfigurations) { + this.validateConfigurationDocument(config); } - - return Promise.resolve(propValue); } /** - * Process and store all secure properties and replace them with a constant for display purposes - * @param name - the name of the profile with which the secure properties are associated - * @param {IProfile} profile - Profile contents to be processed - * @return {Promise} + * Accessor for the logger instance - passed on the constructor + * @readonly + * @protected + * @type {Logger} + * @memberof CliProfileManager */ - private async processSecureProperties(name: string, profile: IProfile): Promise { - // If the credential manager is null, skip secure props and the profile will default to plain text - let securelyStoreValue: SecureOperationFunction; - if (CredentialManagerFactory.initialized) { - /** - * Securely store a property associated with a given profile - * @param {string} propertyNamePath - The path to the property - * @param {string} propertyValue - The value associated with the given profile property - * @return {Promise} - */ - securelyStoreValue = async (propertyNamePath: string, propertyValue: string): Promise => { - if (propertyValue == null) { - // don't store null values but still remove value that may have been stored previously - this.log.debug(`Deleting secured field with key ${propertyNamePath}` + - ` for profile (of type "${this.profileType}").`); - - // In this particular case, do not throw an error if delete doesn't work. - try { - await CredentialManagerFactory.manager.delete( - ProfileUtils.getProfilePropertyKey(this.profileType, name, propertyNamePath) - ); - } catch (err) { - // If delete did not work here, it is probably okay. - } - - return undefined; - } - try { - this.log.debug(`Associating secured field with key ${propertyNamePath}` + - ` for profile (of type "${this.profileType}").`); - // Use the Credential Manager to store the credentials - await CredentialManagerFactory.manager.save( - ProfileUtils.getProfilePropertyKey(this.profileType, name, propertyNamePath), - JSON.stringify(propertyValue) // Stringify it before saving it. We will parse after loading it - ); - } catch (err) { - this.log.error(`Unable to store secure field "${propertyNamePath}" ` + - `associated with profile "${name}" of type "${this.profileType}".`); - - let additionalDetails: string = err.message + (err.additionalDetails ? `\n${err.additionalDetails}` : ""); - additionalDetails = this.addProfileInstruction(additionalDetails); - this.log.error(`Error: ${additionalDetails}`); - - throw new ImperativeError({ - msg: `Unable to store the secure field "${propertyNamePath}" associated with ` + - `the profile "${name}" of type "${this.profileType}".`, - additionalDetails, - causeErrors: err - }); - } - - // The text in the profile will read "managed by " - return `${ProfilesConstants.PROFILES_OPTION_SECURELY_STORED} ${CredentialManagerFactory.manager.name}`; - }; - } - - for (const prop of Object.keys(this.profileTypeConfiguration.schema.properties)) { - profile[prop] = await this.findOptions(this.profileTypeConfiguration.schema.properties[prop], prop, profile[prop], securelyStoreValue); - } - - return profile; + protected get log(): Logger { + return this.mLogger; } /** - * Update an existing profile with arguments from the user based on - * the schema and configuration for this profile type - * @param {IUpdateProfileFromCliArgs} parms - parameters including args - * @param {IProfile} oldProfile - the pre-existing profile to update - * @param {IProfile} newProfile - new profile which will have fields set from CLI args - * @returns {Promise} promise which provides the finished profile on fulfill + * Accessor for the profile type specified on the constructor. + * @readonly + * @protected + * @type {string} + * @memberof CliProfileManager */ - private async updateProfileFromCliArgs(parms: IUpdateProfileFromCliArgs, oldProfile: IProfile, newProfile: IProfile): Promise { - // Create the modified profile from the CLI arguments - const updatedProfile = await this.updateProfileFieldsFromCommandArguments(oldProfile, newProfile, parms.args, parms.merge); - // Save the profile (basically just overwrites the old profile) - let createResponse: IProfileSaved; - try { - this.log.info("Saving updated profile \"%s\" of type \"%s\"", - parms.name, this.profileType); - createResponse = await this.saveProfile({ - name: parms.name, - type: this.profileType, - profile: updatedProfile, - updateDefault: false, - overwrite: true, - }); - } catch (saveErr) { - throw new ImperativeError({ - msg: `An error occurred while saving the modified profile ` + - `("${parms.name}" of type "${this.profileType}"): ${saveErr.message}` - }); - } - - // Return the success response - return { - profile: updatedProfile, - path: createResponse.path, - message: `Profile "${parms.name}" of type "${this.profileType}" successfully updated from command line arguments.` - }; + protected get profileType(): string { + return this.mProfileType; } /** - * - * If a custom handler is provided for update, the handler will be loaded and invoked - * in order to build the finished profile - * @param {IProfile} oldProfile - the old profile to update - * @param newProfile - new profile which may have fields populated, which will be updated from the CLI args - * @param {yargs.Arguments} newArguments - CLi arguments specified by the user - * @param merge - should the profiles be merged? (will be skipped if there is a custom update profile handler) - * @returns {Promise} - promise which provides the finished profile on fulfill + * Accesor for the product display name. + * @readonly + * @protected + * @type {string} + * @memberof CliProfileManager */ - private async updateProfileFieldsFromCommandArguments(oldProfile: IProfile, newProfile: IProfile, newArguments: Arguments, - merge: boolean): Promise { - const profileConfig = this.profileTypeConfiguration; - if (profileConfig.updateProfileFromArgumentsHandler != null) { - // if there is a custom update profile handler, they can call mergeProfile - // from their handler, so we will not do it for them to avoid issues - this.log.debug("Loading custom update profile handler: " + profileConfig.updateProfileFromArgumentsHandler); - const response = new CommandResponse({silent: true}); - let handler: ICommandHandler; - try { - const commandHandler: ICommandHandlerRequire = require(profileConfig.updateProfileFromArgumentsHandler); - handler = new commandHandler.default(); - } catch (e) { - const errorMessage = this.log.error(`Error encountered loading custom update profile handler ` + - `${profileConfig.updateProfileFromArgumentsHandler}:\n` + +e.message); - throw new ImperativeError( - { - msg: errorMessage, - causeErrors: [e], - stack: e.stack - }); - } - try { - await handler.process({ - arguments: CliUtils.buildBaseArgs(newArguments), - positionals: newArguments._, - response, - fullDefinition: undefined, - definition: undefined, - profiles: new CommandProfiles(new Map()), - stdin: process.stdin - }); - } catch (invokeErr) { - const errorMessage = this.log.error(`Error encountered updating profile of type ${this.profileType} ` + - ` with custom update profile handler ` + - `("${profileConfig.updateProfileFromArgumentsHandler}"):` + - invokeErr.message); - throw new ImperativeError( - { - msg: errorMessage, - causeErrors: [invokeErr], - stack: invokeErr.stack - }); - } - - // zeroth response object is specified to be - // the finalized profile - const finishedProfile = response.buildJsonResponse().data; - this.insertDependenciesIntoProfileFromCLIArguments(newArguments, finishedProfile); - return finishedProfile; - } else { - this.log.debug("No custom update profile handler was specified. Building profile from CLI arguments"); - await this.insertCliArgumentsIntoProfile(newArguments, newProfile); - if (merge) { - this.log.debug("Merging new profile created from CLI arguments with existing profile"); - newProfile = this.mergeProfiles(oldProfile, newProfile); - } - return newProfile; - } + protected get productDisplayName(): string { + return this.mProductDisplayName; } /** - * Take command line arguments from the user and create a profile from them using the schema and configuration for - * the profile type - * @param {yargs.Arguments} profileArguments - CLI arguments specified by the user - * @param {IProfile} starterProfile - the profile with name and type to use to start the profile creation - * @returns {Promise} profile which provides the finished profile on fulfill + * Accessor for the full set of type configurations - passed on the constructor. + * @readonly + * @protected + * @type {ICommandProfileTypeConfiguration[]} + * @memberof CliProfileManager */ - private async createProfileFromCommandArguments(profileArguments: Arguments, starterProfile: IProfile): Promise { - const profileConfig = this.profileTypeConfiguration; - if (profileConfig.createProfileFromArgumentsHandler != null) { - const response = new CommandResponse({silent: true, args: profileArguments}); - let handler: ICommandHandler; - try { - const commandHandler: ICommandHandlerRequire = require(profileConfig.createProfileFromArgumentsHandler); - handler = new commandHandler.default(); - } catch (e) { - const errorMessage = this.log.error(`Error encountered loading custom create profile handler ` + - `${profileConfig.createProfileFromArgumentsHandler}:\n` + +e.message); - throw new ImperativeError( - { - msg: errorMessage, - causeErrors: [e], - stack: e.stack - }); - } - try { - await handler.process({ - arguments: CliUtils.buildBaseArgs(profileArguments), - positionals: profileArguments._, - response, - fullDefinition: undefined, - definition: undefined, - profiles: new CommandProfiles(new Map()), - stdin: process.stdin - }); - } catch (invokeErr) { - const errorMessage = this.log.error("Error encountered building new profile with custom create profile handler:" + invokeErr.message); - throw new ImperativeError( - { - msg: errorMessage, - causeErrors: [invokeErr], - stack: invokeErr.stack - }); - } - - // zeroth response object is specified to be - // the finalized profile - const finishedProfile = response.buildJsonResponse().data; - this.insertDependenciesIntoProfileFromCLIArguments(profileArguments, finishedProfile); - - return finishedProfile; - } else { - const profile: IProfile = {}; - // default case - no custom handler - // build profile object directly from command arguments - await this.insertCliArgumentsIntoProfile(profileArguments, profile); - this.insertDependenciesIntoProfileFromCLIArguments(profileArguments, profile); - return profile; - } + protected get profileTypeConfigurations(): ICommandProfileTypeConfiguration[] { + return this.mProfileTypeConfigurations; } /** - * Default style of building of profile fields to option definitions defined in the schema - * Will only work if there is a one-to-one option definition mapping for schema fields - * @param {yargs.Arguments} args - the arguments specified by the user - * @param {IProfile} profile - the profile so far, which will be updated + * Validate that the schema document passed is well formed for the profile manager usage. Ensures that the + * schema is not overloading reserved properties. + * @private + * @param {IProfileSchema} schema - The schema document to validate. + * @param type - the type of profile for the schema - defaults to the current type for this manager + * @memberof CliProfileManager */ - private async insertCliArgumentsIntoProfile(args: Arguments, profile: IProfile): Promise { - /** - * Helper routine to find nested properties - * @param {Object} property - profile property - * @param {ICommandProfileProperty} property - profile property - * @param {string} propertyNamePath - Dot notation path of a property (e.g. my.nested.property) - */ - const findOptions = async (property: ICommandProfileProperty, propertyNamePath: string): Promise => { - if (property.optionDefinition != null) { - // once we reach a property with an option definition, - // we now have the complete path to the property - // so we will set the value on the property from the profile - this.log.debug("Setting profile field %s from command line option %s", propertyNamePath, property.optionDefinition.name); - return args[property.optionDefinition.name]; - } - - if (property.properties != null) { - const tempProperties: any = {}; - for (const childPropertyName of Object.keys(property.properties)) { - tempProperties[childPropertyName] = - await findOptions(property.properties[childPropertyName], propertyNamePath + "." + childPropertyName); - } - return tempProperties; - } - - // Don't define any value here if the profile field cannot be set by a CLI option - return undefined; - }; - - for (const propertyName of Object.keys(this.profileTypeConfiguration.schema.properties)) { - profile[propertyName] = - await findOptions(this.profileTypeConfiguration.schema.properties[propertyName], propertyName); - } + private validateSchema(schema: IProfileSchema, type = this.profileType) { + ImperativeExpect.keysToBeDefined(schema, ["properties"], `The schema document supplied for the profile type ` + + `("${type}") does NOT contain properties.`); + ImperativeExpect.keysToBeUndefined(schema, ["properties.dependencies"], `The schema "properties" property ` + + `(on configuration document for type "${type}") contains "dependencies". ` + + `"dependencies" is must be supplied as part of the "type" configuration document (no need to formulate the dependencies ` + + `schema yourself).`); } /** - * Build the "dependencies" field of a profile object from command line arguments - * @param {yargs.Arguments} args - the command line arguments from the user - * @param {IProfile} profile - the profile object so far. + * Validates the basic configuration document to ensure it contains all the proper fields + * @private + * @param {ICommandProfileTypeConfiguration} typeConfiguration - The type configuration document + * @memberof CliProfileManager */ - private insertDependenciesIntoProfileFromCLIArguments(args: Arguments, profile: IProfile): void { - if (this.profileTypeConfiguration.dependencies != null) { - const dependencies: Array<{ type: string, name: string }> = []; - for (const dependency of this.profileTypeConfiguration.dependencies) { - const optionName = ProfileUtils.getProfileOption(dependency.type); - if (args[optionName] != null) { - const dependentProfileName = args[optionName]; - this.log.debug("Inserting dependency profile named \"%s\" of type \"%s\"", dependentProfileName, dependency.type); - dependencies.push({ - type: dependency.type, - name: dependentProfileName as string - }); - } + private validateConfigurationDocument(typeConfiguration: ICommandProfileTypeConfiguration) { + ImperativeExpect.keysToBeDefinedAndNonBlank(typeConfiguration, ["type"], `The profile type configuration document for ` + + `"${typeConfiguration.type}" does NOT contain a type.`); + ImperativeExpect.keysToBeDefined(typeConfiguration, ["schema"], `The profile type configuration document for ` + + `"${typeConfiguration.type}" does NOT contain a schema.`); + this.validateSchema(typeConfiguration.schema, typeConfiguration.type); + if (!isNullOrUndefined(typeConfiguration.dependencies)) { + ImperativeExpect.toBeAnArray(typeConfiguration.dependencies, + `The profile type configuration for "${typeConfiguration.type}" contains a "dependencies" property, ` + + `but it is not an array (ill-formed)`); + for (const dep of typeConfiguration.dependencies) { + ImperativeExpect.keysToBeDefinedAndNonBlank(dep, ["type"], "A dependency specified for the " + + "profile definitions did not contain a type."); } - profile.dependencies = dependencies; } } - } diff --git a/packages/imperative/src/cmd/src/profiles/CommandProfileLoader.ts b/packages/imperative/src/cmd/src/profiles/CommandProfileLoader.ts index b990ad8952..643ea4a2d5 100644 --- a/packages/imperative/src/cmd/src/profiles/CommandProfileLoader.ts +++ b/packages/imperative/src/cmd/src/profiles/CommandProfileLoader.ts @@ -11,39 +11,30 @@ import { Arguments } from "yargs"; import { ICommandDefinition } from "../doc/ICommandDefinition"; -import { IProfile, IProfileLoaded, IProfileManagerFactory, ProfileUtils } from "../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../doc/profiles/definition/ICommandProfileTypeConfiguration"; +import { IProfile, IProfileLoaded } from "../../../profiles"; import { CommandProfiles } from "./CommandProfiles"; -import { inspect, isNullOrUndefined } from "util"; -import { ICommandLoadProfile } from "../doc/profiles/parms/ICommandLoadProfile"; +import { inspect } from "util"; import { ICommandProfileLoaderParms } from "../doc/profiles/parms/ICommandProfileLoaderParms"; import { Logger } from "../../../logger"; import { ImperativeExpect } from "../../../expect"; -import { ImperativeError } from "../../../error"; -import { ImperativeConfig } from "../../../utilities"; /** * The command processor profile loader loads all profiles that are required (or optional) given a command * definitions requirements. It returns the CommandProfiles object (which contains the map and getters for the * command handlers usage). - * @export + * @internal * @class CommandProfileLoader */ export class CommandProfileLoader { /** * Create a new instance of the profile loader * @static - * @param {CommandResponse} response - The command response object, used to formulate messages, logs and errors - * @param {ICommandDefinition} commandDefinition - The command definition for the command being issued (used to determine - * what profiles to load for this command) - * @param {IProfileManagerFactory} factory - The profile manager factory (used to - * obtain instances of profile managers for profiles that are to be loaded) + * @param {ICommandProfileLoaderParms} parms - contains command definition and logger * @returns * @memberof CommandProfileLoader */ public static loader(parms: ICommandProfileLoaderParms) { - return new CommandProfileLoader(parms.commandDefinition, parms.profileManagerFactory, - parms.logger || Logger.getImperativeLogger()); + return new CommandProfileLoader(parms.commandDefinition, parms.logger || Logger.getImperativeLogger()); } /** @@ -54,14 +45,6 @@ export class CommandProfileLoader { */ private mCommandDefinition: ICommandDefinition; - /** - * The factory for getting profile manager instances. - * @private - * @type {IProfileManagerFactory} - * @memberof CommandProfileLoader - */ - private mFactory: IProfileManagerFactory; - /** * Logger - supplied on the constructor - but defaults to the Imperative logger. * @private @@ -73,17 +56,13 @@ export class CommandProfileLoader { /** * Creates an instance of CommandProfileLoader. * @param {ICommandDefinition} commandDefinition - The input command definition for the command being issued. - * @param {IProfileManagerFactory} factory - The profile manager factory * @param {any} [logger=Logger.getImperativeLogger()] - A log4js instance * @memberof CommandProfileLoader */ - constructor(commandDefinition: ICommandDefinition, factory: IProfileManagerFactory, - logger = Logger.getImperativeLogger()) { + constructor(commandDefinition: ICommandDefinition, logger = Logger.getImperativeLogger()) { const err: string = "Could not construct the profile loader."; ImperativeExpect.toNotBeNullOrUndefined(commandDefinition, `${err} No command definition supplied.`); - ImperativeExpect.toNotBeNullOrUndefined(factory, `${err} No profile factory supplied.`); this.mCommandDefinition = commandDefinition; - this.mFactory = factory; ImperativeExpect.toBeEqual((logger instanceof Logger), true, `${err} The "logger" supplied is not of type Logger.`); this.mLog = logger; this.log.trace(`Profile loader created for command: ${commandDefinition.name}`); @@ -109,192 +88,8 @@ export class CommandProfileLoader { const profileMap: Map = new Map(); const profileMetaMap: Map = new Map(); - // do not load old school profiles if we are in team-config mode - if (ImperativeConfig.instance.config?.exists) { - return new CommandProfiles(profileMap, profileMetaMap); - } - - // If there are no profile specifications on this command definition document node, then - // we can immediately exit with an empty map - if (!isNullOrUndefined(this.definition.profile)) { - this.log.trace(`Loading profiles for command: ${this.definition.name}...`); - const loadList: ICommandLoadProfile[] = this.constructLoadList(commandArguments); - const responses: IProfileLoaded[] = await this.loadAll(loadList); - this.log.debug(`"${responses.length}" profiles loaded.`); - this.buildCommandMap(responses, profileMap); - this.buildCommandMetaMap(responses, profileMetaMap); - this.log.trace(`All profiles loaded for command: ${this.definition.name}...`); - } - - // Return the command profiles object for the handler + // We no longer read V1 profile files, so just return empty maps return new CommandProfiles(profileMap, profileMetaMap); - - } - - /** - * Builds the command map for input the the command map object for the command handlers - * @private - * @param {IProfileLoaded[]} responses - The full list of profiles loaded for this command - * @param {Map} map - The map to populate - * @memberof CommandProfileLoader - */ - private buildCommandMap(responses: IProfileLoaded[], map: Map) { - for (const resp of responses) { - if (resp.profile) { - if (isNullOrUndefined(map.get(resp.type))) { - this.log.trace(`Adding first profile "${resp.name}" of type "${resp.type}" to the map.`); - map.set(resp.type, [resp.profile]); - } else { - this.log.trace(`Adding profile "${resp.name}" of type "${resp.type}" to the map.`); - const existing = map.get(resp.type); - existing.push(resp.profile); - } - } else { - this.log.debug(`Profile load response without a profile: ${resp.message}`); - } - } - } - - /** - * Builds the command meta map for input the the command map object for the command handlers - * @private - * @param {IProfileLoaded[]} responses - The full list of profiles loaded for this command - * @param {Map} map - The meta map to populate - * @memberof CommandProfileLoader - */ - private buildCommandMetaMap(responses: IProfileLoaded[], map: Map) { - for (const resp of responses) { - if (resp.profile) { - if (isNullOrUndefined(map.get(resp.type))) { - this.log.trace(`Adding first profile "${resp.name}" of type "${resp.type}" to the map.`); - map.set(resp.type, [resp]); - } else { - this.log.trace(`Adding profile "${resp.name}" of type "${resp.type}" to the map.`); - const existing = map.get(resp.type); - existing.push(resp); - } - } else { - this.log.debug(`Profile load response without a profile: ${resp.message}`); - } - } - } - - /** - * Builds the list of profiles to load for this command. - * @private - * @param {Arguments} commandArguments - The arguments supplied on the command (Yargs Style) - * @returns {ICommandLoadProfile[]} - The list of profiles to load (and other control information) - * @memberof CommandProfileLoader - */ - private constructLoadList(commandArguments: Arguments): ICommandLoadProfile[] { - let loadProfiles: ICommandLoadProfile[] = []; - this.log.trace(`Building required profiles for the load list...`); - loadProfiles = this.buildLoad(false, this.definition.profile.required, commandArguments); - this.log.trace(`Building optional profiles to the load list...`); - return loadProfiles.concat(this.buildLoad(true, this.definition.profile.optional, commandArguments)); - } - - /** - * Builds the control parameters for the loading of each profile name/type. - * @private - * @param {boolean} optional - If the profile is optional - * @param {string[]} types - The profile types to load - * @param {Arguments} commandArguments - The command arguments - * @returns {ICommandLoadProfile[]} - The list of profiles to load (and control parameters) - * @memberof CommandProfileLoader - */ - private buildLoad(optional: boolean, types: string[], commandArguments: Arguments): ICommandLoadProfile[] { - const loadProfiles: ICommandLoadProfile[] = []; - if (!isNullOrUndefined(types)) { - // Construct the load control parameters for each required type - types.forEach((type) => { - - // Assume some defaults - const load: ICommandLoadProfile = { - name: undefined, - type, - userSpecified: false, - loadDefault: false, - optional - }; - - // If the argument is specified, indicate that this is a user specified load and if not - // assume that the default should be loaded (but still required on the command) - const profOpt = ProfileUtils.getProfileOptionAndAlias(type)[0]; - if (!isNullOrUndefined(commandArguments[profOpt])) { - load.userSpecified = true; - load.name = commandArguments[profOpt] as string; - } else { - load.loadDefault = true; - } - - // Add to the list - this.log.trace(`Adding load parameters to list: ${inspect(load, {depth: null})}`); - loadProfiles.push(load); - }); - } - - // Return the list - return loadProfiles; - } - - /** - * Invoke the profile managers to load the profiles requested for this command. - * @private - * @param {ICommandLoadProfile[]} list - The list of profiles to load and control parameters. - * @returns {Promise} - The promise to fulfill with the entire load response OR rejected with - * an Imperative Error. - * @memberof CommandProfileLoader - */ - private async loadAll(list: ICommandLoadProfile[]): Promise { - - // Attempt to load each profile indicated by the load control parameters - const loadResponses: IProfileLoaded[] = []; - for (const load of list) { - this.log.debug(`Loading profile "${load.name}" of type "${load.type}".`); - const response = await this.factory.getManager(load.type).load({ - loadDefault: load.loadDefault, - name: load.name, - failNotFound: !load.optional - }); - - // This is an exceptional case - the manager did not do it's job properly, but we will ensure - // that if a profile was required (not optional), that it was loaded. - if (!load.optional && (isNullOrUndefined(response) || isNullOrUndefined(response.profile))) { - throw new ImperativeError({ - msg: `Unexpected internal load error: The profile ` + - `"${(load.loadDefault) ? "default requested" : load.name}" was not loaded by the profile manager.` - }); - } - - // Push the loaded resposne - this.log.debug(`Adding dependencies "${response.name}" of type "${response.type}"`); - loadResponses.push(response); - - // If dependencies have been loaded, we'll flatten the tree and push on the response list. - if (response.dependenciesLoaded) { - this.log.trace(`Dependencies have also been loaded, adding to list...`); - const flatten = ProfileUtils.flattenDependencies(response.dependencyLoadResponses); - for (const flat of flatten) { - this.log.debug(`Adding dependencies "${flat.name}" of type "${flat.type}"`); - loadResponses.push(flat); - } - } - } - - // Return the full list of load responses - return loadResponses; - } - - /** - * Accessor for the profile manager factory - * @readonly - * @private - * @type {IProfileManagerFactory} - * @memberof CommandProfileLoader - */ - private get factory(): IProfileManagerFactory { - return this.mFactory; } /** diff --git a/packages/imperative/src/cmd/src/profiles/CommandProfiles.ts b/packages/imperative/src/cmd/src/profiles/CommandProfiles.ts index 001dc1a14c..b75bd5cff4 100644 --- a/packages/imperative/src/cmd/src/profiles/CommandProfiles.ts +++ b/packages/imperative/src/cmd/src/profiles/CommandProfiles.ts @@ -15,8 +15,7 @@ import { ImperativeExpect } from "../../../expect"; /** * Profiles map created by the command profile loader and passed to the handler via parameters. Handlers can - * retreive loaded profiles from the map via the profile type. - * @export + * retrieve loaded profiles from the map via the profile type. * @class CommandProfiles */ export class CommandProfiles { @@ -62,43 +61,38 @@ export class CommandProfiles { } /** - * Gets the first (or by name) meta profile in the map - automatically throws an exception (unless disabled) - * @deprecated - * @template T - The expected profile mapping to be returned - * @param {string} type - The profile type - * @param {string} [name=""] - The name of the profile to retrieve - * @param {boolean} [failNotFound=true] - Automatically throws an imperative exception if not profiles are not - * found - this is provided as convince for the handlers (will fail your command if not found) - This would - * normally be the result of a command configuration problem. - * @returns {T} - The first profile in the map (or the one located by name) + * Add to an instance of CommandProfiles + * @private + * @param {Map} map - The map of profiles with meta information * @memberof CommandProfiles */ - public getMeta(type: string, failNotFound = true, name = ""): T { - let profile: IProfileLoaded; - // If a profile is returned for the type, then we'll check if a profile of a specific name was requseted - // if not, just return the first profile found (first loaded) - if (this.metaMap.get(type) != null) { - if (name != null && name.trim().length > 0) { - for (const prof of this.metaMap.get(type)) { + private addMeta(map: Map) { + // Simple validation of input parameters + const err: string = "Command Profiles Internal Error:"; + ImperativeExpect.toNotBeNullOrUndefined(map, `${err} No map was supplied.`); + ImperativeExpect.toBeEqual(map instanceof Map, true, `${err} The "map" supplied is not an instance of a map.`); - if (prof.name === name) { - profile = prof; - break; - } - } - } else { - profile = this.metaMap.get(type)[0]; - } - } else if (failNotFound) { - this.fail(type); - } - return profile as T; + // Ensure the correctness of each map entry + map.forEach((value, key) => { + ImperativeExpect.toBeAnArray(value, `${err} The "profiles" supplied for type "${key}" is NOT an array.`); + ImperativeExpect.toBeEqual((value.length > 0), true, `${err} No profiles supplied for type "${key}".`); + }); + this.mMetaMap = map; } + /** + * Internal accessor for the map + * @readonly + * @private + * @type {Map} - The profile Map + * @memberof CommandProfiles + */ + private get map(): Map { + return this.mMap; + } /** * Gets the first (or by name) profile in the map - automatically throws an exception (unless disabled) - * @deprecated Load profile properties from `IHandlerParameters.arguments` property instead. * @template T - The expected profile mapping to be returned * @param {string} type - The profile type * @param {string} [name=""] - The name of the profile to retrieve @@ -130,56 +124,6 @@ export class CommandProfiles { return profile as T; } - /** - * Gets all profiles for the type specified, - * @deprecated - * @template T - extends IProfile - * @param {string} type - The profile type to retrieve loaded profiles - * @returns {T[]} - The list of profile types - * @param {boolean} [failNotFound=true] - Automatically throws an imperative exception if not profiles are not - * found - this is provided as convince for the handlers (will fail your command if not found) - This would - * normally be the result of a command configuration problem. - * @memberof CommandProfiles - */ - public getAll(type: string, failNotFound = true): T[] { - const profiles: IProfile[] = this.map.get(type); - if (profiles == null && failNotFound) { - this.fail(type); - } - return profiles as T[]; - } - - /** - * Add to an instance of CommandProfiles - * @private - * @param {Map} map - The map of profiles with meta information - * @memberof CommandProfiles - */ - private addMeta(map: Map) { - // Simple validation of input parameters - const err: string = "Command Profiles Internal Error:"; - ImperativeExpect.toNotBeNullOrUndefined(map, `${err} No map was supplied.`); - ImperativeExpect.toBeEqual(map instanceof Map, true, `${err} The "map" supplied is not an instance of a map.`); - - // Ensure the correctness of each map entry - map.forEach((value, key) => { - ImperativeExpect.toBeAnArray(value, `${err} The "profiles" supplied for type "${key}" is NOT an array.`); - ImperativeExpect.toBeEqual((value.length > 0), true, `${err} No profiles supplied for type "${key}".`); - }); - this.mMetaMap = map; - } - - /** - * Internal accessor for the map - * @readonly - * @private - * @type {Map} - The profile Map - * @memberof CommandProfiles - */ - private get map(): Map { - return this.mMap; - } - /** * Internal accessor for the meta map * @readonly diff --git a/packages/imperative/src/cmd/src/yargs/AbstractCommandYargs.ts b/packages/imperative/src/cmd/src/yargs/AbstractCommandYargs.ts index 60c19b7059..78b4621b6e 100644 --- a/packages/imperative/src/cmd/src/yargs/AbstractCommandYargs.ts +++ b/packages/imperative/src/cmd/src/yargs/AbstractCommandYargs.ts @@ -19,8 +19,6 @@ import { IYargsParms } from "./doc/IYargsParms"; import { ICommandResponseParms } from "../../../cmd/src/doc/response/parms/ICommandResponseParms"; import { ImperativeYargsCommandAction, IYargsResponse } from "./doc/IYargsResponse"; import { GroupCommandYargs } from "./GroupCommandYargs"; -import { IProfileManagerFactory } from "../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../doc/profiles/definition/ICommandProfileTypeConfiguration"; import { IHelpGeneratorFactory } from "../help/doc/IHelpGeneratorFactory"; import { CommandResponse } from "../response/CommandResponse"; import { ICommandResponse } from "../../src/doc/response/response/ICommandResponse"; @@ -68,14 +66,6 @@ export abstract class AbstractCommandYargs { */ private mHelpGeneratorFactory: IHelpGeneratorFactory; - /** - * Profile manager factory (for creating managers of certain types) - * @private - * @type {IProfileManagerFactory} - * @memberof AbstractCommandYargs - */ - private mProfileManagerFactory: IProfileManagerFactory; - /** * The root command name for the CLI. * @private @@ -117,7 +107,6 @@ export abstract class AbstractCommandYargs { this.mDefinition = yargsParms.commandDefinition; this.mParent = yargsParms.yargsParent; this.mCommandResponseParms = yargsParms.commandResponseParms; - this.mProfileManagerFactory = yargsParms.profileManagerFactory; this.mHelpGeneratorFactory = yargsParms.helpGeneratorFactory; this.mRootCommandName = yargsParms.rootCommandName; this.mCommandLine = yargsParms.commandLine; @@ -186,16 +175,6 @@ export abstract class AbstractCommandYargs { return this.mHelpGeneratorFactory; } - /** - * Accessor for the profile manager factory - * @readonly - * @type {IProfileManagerFactory} - * @memberof AbstractCommandYargs - */ - protected get profileManagerFactory(): IProfileManagerFactory { - return this.mProfileManagerFactory; - } - /** * Returns a copy of the definition. * @return {ICommandDefinition}: A copy of the definition. @@ -297,7 +276,6 @@ export abstract class AbstractCommandYargs { definition: tempDefinition ? tempDefinition : this.definition, fullDefinition: tempDefinition ? tempDefinition : this.constructDefinitionTree(), helpGenerator: newHelpGenerator, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: this.commandLine, envVariablePrefix: this.envVariablePrefix, @@ -409,7 +387,6 @@ export abstract class AbstractCommandYargs { definition: this.definition, fullDefinition: this.constructDefinitionTree(), helpGenerator: "fake" as any, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: this.commandLine, envVariablePrefix: this.envVariablePrefix, diff --git a/packages/imperative/src/cmd/src/yargs/CommandYargs.ts b/packages/imperative/src/cmd/src/yargs/CommandYargs.ts index e2481afdda..92a3098916 100644 --- a/packages/imperative/src/cmd/src/yargs/CommandYargs.ts +++ b/packages/imperative/src/cmd/src/yargs/CommandYargs.ts @@ -223,7 +223,6 @@ export class CommandYargs extends AbstractCommandYargs { fullCommandTree: this.constructDefinitionTree(), experimentalCommandsDescription: this.yargsParms.experimentalCommandDescription }), - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: ImperativeConfig.instance.commandLine, envVariablePrefix: this.envVariablePrefix, diff --git a/packages/imperative/src/cmd/src/yargs/GroupCommandYargs.ts b/packages/imperative/src/cmd/src/yargs/GroupCommandYargs.ts index e997dac74d..c7971d86bd 100644 --- a/packages/imperative/src/cmd/src/yargs/GroupCommandYargs.ts +++ b/packages/imperative/src/cmd/src/yargs/GroupCommandYargs.ts @@ -61,7 +61,6 @@ export class GroupCommandYargs extends AbstractCommandYargs { yargsParent: this, commandResponseParms: this.responseParms, helpGeneratorFactory: this.helpGeneratorFactory, - profileManagerFactory: this.profileManagerFactory, experimentalCommandDescription: this.yargsParms.experimentalCommandDescription, rootCommandName: this.rootCommandName, commandLine: this.commandLine, @@ -76,7 +75,6 @@ export class GroupCommandYargs extends AbstractCommandYargs { yargsParent: this, commandResponseParms: this.responseParms, helpGeneratorFactory: this.helpGeneratorFactory, - profileManagerFactory: this.profileManagerFactory, experimentalCommandDescription: this.yargsParms.experimentalCommandDescription, rootCommandName: this.rootCommandName, commandLine: this.commandLine, diff --git a/packages/imperative/src/cmd/src/yargs/YargsConfigurer.ts b/packages/imperative/src/cmd/src/yargs/YargsConfigurer.ts index 51c1f0c10d..e921ab63b9 100644 --- a/packages/imperative/src/cmd/src/yargs/YargsConfigurer.ts +++ b/packages/imperative/src/cmd/src/yargs/YargsConfigurer.ts @@ -18,8 +18,6 @@ import { ICommandDefinition } from "../doc/ICommandDefinition"; import { ICommandResponseParms } from "../doc/response/parms/ICommandResponseParms"; import { CommandProcessor } from "../CommandProcessor"; import { CommandUtils } from "../utils/CommandUtils"; -import { IProfileManagerFactory } from "../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../doc/profiles/definition/ICommandProfileTypeConfiguration"; import { IHelpGeneratorFactory } from "../help/doc/IHelpGeneratorFactory"; import { ImperativeConfig } from "../../../utilities"; import { closest } from "fastest-levenshtein"; @@ -33,7 +31,6 @@ export class YargsConfigurer { constructor(private rootCommand: ICommandDefinition, private yargs: any, private commandRespParms: ICommandResponseParms, - private profileManagerFactory: IProfileManagerFactory, private helpGeneratorFactory: IHelpGeneratorFactory, private experimentalCommandDescription: string, private rootCommandName: string, @@ -74,7 +71,6 @@ export class YargsConfigurer { new CommandProcessor({ definition: this.rootCommand, fullDefinition: this.rootCommand, helpGenerator: rootHelpGenerator, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: this.commandLine, envVariablePrefix: this.envVariablePrefix, @@ -108,7 +104,6 @@ export class YargsConfigurer { definition: failedCommandDefinition, fullDefinition: failedCommandDefinition, helpGenerator: rootHelpGenerator, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: ImperativeConfig.instance.commandLine, envVariablePrefix: this.envVariablePrefix, @@ -144,7 +139,6 @@ export class YargsConfigurer { definition: failedCommandDefinition, fullDefinition: failedCommandDefinition, helpGenerator: failHelpGenerator, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: this.commandLine, envVariablePrefix: this.envVariablePrefix, @@ -187,7 +181,6 @@ export class YargsConfigurer { definition: failedCommandDefinition, fullDefinition: failedCommandDefinition, helpGenerator: failHelpGenerator, - profileManagerFactory: this.profileManagerFactory, rootCommandName: this.rootCommandName, commandLine: ImperativeConfig.instance.commandLine, envVariablePrefix: this.envVariablePrefix, diff --git a/packages/imperative/src/cmd/src/yargs/YargsDefiner.ts b/packages/imperative/src/cmd/src/yargs/YargsDefiner.ts index ae850eee1a..b6b0e6cf09 100644 --- a/packages/imperative/src/cmd/src/yargs/YargsDefiner.ts +++ b/packages/imperative/src/cmd/src/yargs/YargsDefiner.ts @@ -17,8 +17,6 @@ import { YargsCommandCompleted } from "./AbstractCommandYargs"; import { GroupCommandYargs } from "./GroupCommandYargs"; import { CommandYargs } from "./CommandYargs"; import { ICommandResponseParms } from "../../../cmd/src/doc/response/parms/ICommandResponseParms"; -import { IProfileManagerFactory } from "../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../doc/profiles/definition/ICommandProfileTypeConfiguration"; import { IHelpGeneratorFactory } from "../help/doc/IHelpGeneratorFactory"; /** @@ -34,7 +32,6 @@ export class YargsDefiner { private mCommandLine: string; private mEnvVariablePrefix: string; private mHelpFactory: IHelpGeneratorFactory; - private mProfileManagerFactory: IProfileManagerFactory; private mExperimentalCommandDescription: string; private mPromptPhrase: string; @@ -49,7 +46,6 @@ export class YargsDefiner { * @param primaryHighlightColor - main color to highlight help text headings and other text with * @param rootCommandName - the display name of the root command (e.g. "zowe" or "sample-cli") * @param envVariablePrefix - the environment variable prefix - * @param profileManagerFactory - profile manager factory that can be used to instantiate new profile managers * @param helpGeneratorFactory - help generator factory that can be used to instantiate new help generators * @param experimentalCommandDescription - optionally overridden experimental command description to * propagate to yargs services @@ -59,7 +55,6 @@ export class YargsDefiner { rootCommandName: string, commandLine: string, envVariablePrefix: string, - profileManagerFactory: IProfileManagerFactory, helpGeneratorFactory: IHelpGeneratorFactory, experimentalCommandDescription: string, promptPhrase: string) { @@ -69,7 +64,6 @@ export class YargsDefiner { this.mCommandLine = commandLine; this.mEnvVariablePrefix = envVariablePrefix; this.mHelpFactory = helpGeneratorFactory; - this.mProfileManagerFactory = profileManagerFactory; this.mExperimentalCommandDescription = experimentalCommandDescription; this.mPromptPhrase = promptPhrase; } @@ -96,7 +90,6 @@ export class YargsDefiner { commandDefinition: definition, commandResponseParms: responseParms, helpGeneratorFactory: this.mHelpFactory, - profileManagerFactory: this.mProfileManagerFactory, experimentalCommandDescription: this.mExperimentalCommandDescription, rootCommandName: this.mRootCommandName, commandLine: this.mCommandLine, @@ -110,7 +103,6 @@ export class YargsDefiner { commandDefinition: definition, commandResponseParms: responseParms, helpGeneratorFactory: this.mHelpFactory, - profileManagerFactory: this.mProfileManagerFactory, experimentalCommandDescription: this.mExperimentalCommandDescription, rootCommandName: this.mRootCommandName, commandLine: this.mCommandLine, diff --git a/packages/imperative/src/cmd/src/yargs/doc/IYargsParms.ts b/packages/imperative/src/cmd/src/yargs/doc/IYargsParms.ts index 3d1c8fb4b1..002c31394e 100644 --- a/packages/imperative/src/cmd/src/yargs/doc/IYargsParms.ts +++ b/packages/imperative/src/cmd/src/yargs/doc/IYargsParms.ts @@ -13,7 +13,6 @@ import { Argv } from "yargs"; import { ICommandDefinition } from "../../doc/ICommandDefinition"; import { GroupCommandYargs } from "../GroupCommandYargs"; import { ICommandResponseParms } from "../../doc/response/parms/ICommandResponseParms"; -import { IProfileManagerFactory } from "../../../../profiles"; import { IHelpGeneratorFactory } from "../../help/doc/IHelpGeneratorFactory"; /** @@ -48,12 +47,6 @@ export interface IYargsParms { * @memberof IYargsParms */ helpGeneratorFactory: IHelpGeneratorFactory; - /** - * The profile manager factory to use in this CLI profile management. - * @type {AbstractProfileManagerFactory} - * @memberof IYargsParms - */ - profileManagerFactory: IProfileManagerFactory; /** * Optionally override the experimental command help text block. * Used to propagate the user's configuration down to different yargs/cmd services. diff --git a/packages/imperative/src/config/__tests__/ConfigUtils.unit.test.ts b/packages/imperative/src/config/__tests__/ConfigUtils.unit.test.ts index 7a7abae614..ed5a5b6b14 100644 --- a/packages/imperative/src/config/__tests__/ConfigUtils.unit.test.ts +++ b/packages/imperative/src/config/__tests__/ConfigUtils.unit.test.ts @@ -9,6 +9,8 @@ * */ +import * as fs from "fs"; + import { ConfigUtils } from "../../config/src/ConfigUtils"; import { CredentialManagerFactory } from "../../security"; import { ImperativeConfig } from "../../utilities"; @@ -92,4 +94,59 @@ describe("Config Utils", () => { expect(error.additionalDetails).toBe(solution); }); }); + + describe("onlyV1ProfilesExist", () => { + afterEach(() => { + jest.restoreAllMocks(); // restore spies + jest.clearAllMocks(); // set counts back to zero + }); + + it("should return false when a team config exists", () => { + jest.spyOn(ImperativeConfig, "instance", "get").mockReturnValueOnce({ + config: { + exists: true + } + } as any); + + expect(ConfigUtils.onlyV1ProfilesExist).toBe(false); + }); + + it("should return false when neither team config or v1 profiles exist", () => { + jest.spyOn(ImperativeConfig, "instance", "get").mockReturnValue({ + config: { + exists: false + }, + cliHome: "/fake/cli/home/dir", + loadedConfig: jest.fn(() => { + return { + envVariablePrefix: "Fake_cli_prefix" + }; + }) + } as any); + + const fsExistsSyncSpy = jest.spyOn(fs, "existsSync").mockReturnValueOnce(false); + + expect(ConfigUtils.onlyV1ProfilesExist).toBe(false); + expect(fsExistsSyncSpy).toHaveBeenCalledTimes(1); + }); + + it("should return true when only V1 profiles exist", () => { + jest.spyOn(ImperativeConfig, "instance", "get").mockReturnValue({ + config: { + exists: false + }, + cliHome: "/fake/cli/home/dir", + loadedConfig: jest.fn(() => { + return { + envVariablePrefix: "Fake_cli_prefix" + }; + }) + } as any); + + const fsExistsSyncSpy = jest.spyOn(fs, "existsSync").mockReturnValueOnce(true); + + expect(ConfigUtils.onlyV1ProfilesExist).toBe(true); + expect(fsExistsSyncSpy).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/packages/imperative/src/config/__tests__/ProfileCredentials.unit.test.ts b/packages/imperative/src/config/__tests__/ProfileCredentials.unit.test.ts index cb8c450dae..5b0db2f8cf 100644 --- a/packages/imperative/src/config/__tests__/ProfileCredentials.unit.test.ts +++ b/packages/imperative/src/config/__tests__/ProfileCredentials.unit.test.ts @@ -32,7 +32,6 @@ describe("ProfileCredentials tests", () => { describe("isSecured", () => { it("should be true if team config is not secure but CredentialManager is set", () => { const profCreds = new ProfileCredentials({ - usingTeamConfig: true, getTeamConfig: () => mockConfigApi({ secureFields: () => [] }) } as any); jest.spyOn(profCreds as any, "isCredentialManagerInAppSettings").mockReturnValueOnce(true); @@ -41,7 +40,6 @@ describe("ProfileCredentials tests", () => { it("should be true if team config is secure but CredentialManager is not set", () => { const profCreds = new ProfileCredentials({ - usingTeamConfig: true, getTeamConfig: () => mockConfigApi({ secureFields: () => ["myAwesomeProperty"] }) } as any); jest.spyOn(profCreds as any, "isCredentialManagerInAppSettings").mockReturnValueOnce(false); @@ -50,33 +48,14 @@ describe("ProfileCredentials tests", () => { it("should be false if team config is not secure and CredentialManager is not set", () => { const profCreds = new ProfileCredentials({ - usingTeamConfig: true, getTeamConfig: () => mockConfigApi({ secureFields: () => [] }) } as any); jest.spyOn(profCreds as any, "isCredentialManagerInAppSettings").mockReturnValueOnce(false); expect(profCreds.isSecured).toBe(false); }); - it("should be true for old school profiles if CredentialManager is set", () => { - const profCreds = new ProfileCredentials({ - usingTeamConfig: false - } as any); - jest.spyOn(profCreds as any, "isCredentialManagerInAppSettings").mockReturnValueOnce(true); - expect(profCreds.isSecured).toBe(true); - }); - - it("should be false for old school profiles if CredentialManager is not set", () => { - const profCreds = new ProfileCredentials({ - usingTeamConfig: false - } as any); - jest.spyOn(profCreds as any, "isCredentialManagerInAppSettings").mockReturnValueOnce(false); - expect(profCreds.isSecured).toBe(false); - }); - it("should not be cached for subsequent calls", () => { - const profCreds = new ProfileCredentials({ - usingTeamConfig: true - } as any); + const profCreds = new ProfileCredentials({} as any); jest.spyOn(profCreds as any, "isTeamConfigSecure").mockReturnValueOnce(false).mockReturnValueOnce(true); expect(profCreds.isSecured).toBe(false); // expect a 2nd time to ensure value has changed @@ -106,7 +85,10 @@ describe("ProfileCredentials tests", () => { it("should initialize CredentialManagerFactory once with good credential manager", async () => { const profCreds = new ProfileCredentials({ - usingTeamConfig: false + getTeamConfig: () => mockConfigApi({ + secureFields: () => [], + load: jest.fn() + }) } as any); jest.spyOn(profCreds, "isSecured", "get").mockReturnValue(true); jest.spyOn(CredentialManagerFactory, "initialize").mockImplementation(async () => { @@ -129,9 +111,7 @@ describe("ProfileCredentials tests", () => { }); it("should fail to initialize CredentialManagerFactory with bad credential manager", async () => { - const profCreds = new ProfileCredentials({ - usingTeamConfig: false - } as any); + const profCreds = new ProfileCredentials({} as any); jest.spyOn(profCreds, "isSecured", "get").mockReturnValue(true); jest.spyOn(CredentialManagerFactory, "initialize").mockImplementation(async () => { throw new Error("bad credential manager"); @@ -164,7 +144,10 @@ describe("ProfileCredentials tests", () => { } }; const profCreds = new ProfileCredentials({ - usingTeamConfig: false + getTeamConfig: () => mockConfigApi({ + secureFields: () => ["myAwesomeProperty"], + load: jest.fn() + }), } as any, { credMgrOverride }); jest.spyOn(profCreds, "isSecured", "get").mockReturnValue(true); jest.spyOn(CredentialManagerFactory, "initialize").mockImplementation(async (params: ICredentialManagerInit) => { @@ -186,8 +169,7 @@ describe("ProfileCredentials tests", () => { it("should call Config secure load API when team config enabled", async () => { const mockSecureLoad = jest.fn(); const profCreds = new ProfileCredentials({ - getTeamConfig: () => mockConfigApi({ load: mockSecureLoad }), - usingTeamConfig: true + getTeamConfig: () => mockConfigApi({ load: mockSecureLoad }) } as any); jest.spyOn(profCreds, "isSecured", "get").mockReturnValue(true); jest.spyOn(CredentialManagerFactory, "initialize").mockImplementation(); diff --git a/packages/imperative/src/config/__tests__/ProfileInfo.OldProfiles.unit.test.ts b/packages/imperative/src/config/__tests__/ProfileInfo.OldProfiles.unit.test.ts deleted file mode 100644 index d73f69e081..0000000000 --- a/packages/imperative/src/config/__tests__/ProfileInfo.OldProfiles.unit.test.ts +++ /dev/null @@ -1,561 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import * as path from "path"; -import { ProfileInfo } from "../src/ProfileInfo"; -import { IProfAttrs } from "../src/doc/IProfAttrs"; -import { IProfOpts } from "../src/doc/IProfOpts"; -import { ProfInfoErr } from "../src/ProfInfoErr"; -import { ProfLocType } from "../src/doc/IProfLoc"; -import { IProfileSchema, ProfileIO } from "../../profiles"; -import { ImperativeError } from "../../error"; -import { IProfArgAttrs } from "../src/doc/IProfArgAttrs"; - -const testAppNm = "ProfInfoApp"; -const testEnvPrefix = testAppNm.toUpperCase(); -const profileTypes = ["zosmf", "tso", "base", "dummy"]; - -function createNewProfInfo(newDir: string, opts?: IProfOpts): ProfileInfo { - // create a new ProfileInfo in the desired directory - process.chdir(newDir); - const profInfo = new ProfileInfo(testAppNm, opts); - jest.spyOn((profInfo as any).mCredentials, "isSecured", "get").mockReturnValue(false); - return profInfo; -} - -describe("Old-school ProfileInfo tests", () => { - - const tsoName = "tsoProfName"; - const testDir = path.join(__dirname, "__resources__"); - const homeDirPath = path.join(testDir, testAppNm + "_home"); - const homeDirPathTwo = path.join(testDir, testAppNm + "_home_two"); - const homeDirPathThree = path.join(testDir, testAppNm + "_home_three"); - const four = 4; - let origDir: string; - - beforeAll(() => { - // remember our original directory - origDir = process.cwd(); - }); - - beforeEach(() => { - // set our desired app home directory into the environment - process.env[testEnvPrefix + "_CLI_HOME"] = homeDirPath; - }); - - afterAll(() => { - // ensure that jest reports go to the right place - process.chdir(origDir); - }); - - afterEach(() => { - jest.restoreAllMocks(); - }); - - describe("getDefaultProfile", () => { - - afterEach(() => { - jest.clearAllMocks(); - }); - - it("should return null if no default for that type exists 1", async () => { - const profInfo = createNewProfInfo(homeDirPath); - const warnSpy = jest.spyOn((profInfo as any).mImpLogger, "warn"); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("ThisTypeDoesNotExist"); - expect(profAttrs).toBeNull(); - expect(warnSpy).toHaveBeenCalledTimes(2); - expect(warnSpy).toHaveBeenCalledWith("Found no old-school profile for type 'ThisTypeDoesNotExist'."); - }); - - it("should return null if no default for that type exists 2", async () => { - process.env[testEnvPrefix + "_CLI_HOME"] = homeDirPathTwo; - const profInfo = createNewProfInfo(homeDirPathTwo); - const warnSpy = jest.spyOn((profInfo as any).mImpLogger, "warn"); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf"); - expect(profAttrs).toBeNull(); - expect(warnSpy).toHaveBeenCalledTimes(four); - expect(warnSpy).toHaveBeenLastCalledWith("Found no default old-school profiles."); - }); - - it("should return null if no default for that type exists 3", async () => { - process.env[testEnvPrefix + "_CLI_HOME"] = homeDirPathThree; - const profInfo = createNewProfInfo(homeDirPathThree); - const warnSpy = jest.spyOn((profInfo as any).mImpLogger, "warn"); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf"); - expect(profAttrs).toBeNull(); - expect(warnSpy).toHaveBeenCalledTimes(four); - expect(warnSpy).toHaveBeenLastCalledWith("Found no old-school profiles."); - }); - - it("should return null if profile root dir does not exist", async () => { - const invalidHomeDir = homeDirPath + "_does_not_exist"; - process.env[testEnvPrefix + "_CLI_HOME"] = invalidHomeDir; - const profInfo = new ProfileInfo(testAppNm); - jest.spyOn((profInfo as any).mCredentials, "isSecured", "get").mockReturnValue(false); - await profInfo.readProfilesFromDisk(); - expect(profInfo.getDefaultProfile("zosmf")).toBeNull(); - }); - - it("should return a profile if one exists", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const desiredProfType = "tso"; - const profAttrs = profInfo.getDefaultProfile(desiredProfType) as IProfAttrs; - - expect(profAttrs).not.toBeNull(); - expect(profAttrs.isDefaultProfile).toBe(true); - expect(profAttrs.profName).toBe(tsoName); - expect(profAttrs.profType).toBe(desiredProfType); - expect(profAttrs.profLoc.locType).not.toBeNull(); - - const retrievedOsLoc = path.normalize(profAttrs.profLoc.osLoc[0]); - const expectedOsLoc = path.join(homeDirPath, "profiles", - desiredProfType, profAttrs.profName + ".yaml" - ); - expect(retrievedOsLoc).toBe(expectedOsLoc); - - expect(profAttrs.profLoc.jsonLoc).toBeUndefined(); - }); - }); - - describe("getAllProfiles", () => { - it("should return all profiles if no type is specified", async () => { - const length = 8; - const expectedDefaultProfileNameZosmf = "lpar1_zosmf"; - const expectedDefaultProfileNameTso = "tsoProfName"; - const expectedDefaultProfileNameBase = "base_for_userNm"; - const expectedDefaultProfiles = 3; - let expectedProfileNames = ["lpar1_zosmf", "lpar2_zosmf", "lpar3_zosmf", "lpar4_zosmf", "lpar5_zosmf", "tsoProfName", - "base_for_userNm", "base_apiml"]; - let actualDefaultProfiles = 0; - - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getAllProfiles(); - - expect(profAttrs.length).toEqual(length); - for (const prof of profAttrs) { - if (prof.isDefaultProfile) { - let expectedName = ""; - switch (prof.profType) { - case "zosmf": expectedName = expectedDefaultProfileNameZosmf; break; - case "tso": expectedName = expectedDefaultProfileNameTso; break; - case "base": expectedName = expectedDefaultProfileNameBase; break; - } - expect(prof.profName).toEqual(expectedName); - actualDefaultProfiles += 1; - } - expect(expectedProfileNames).toContain(prof.profName); - expect(profileTypes).toContain(prof.profType); - expect(prof.profLoc.locType).toEqual(ProfLocType.OLD_PROFILE); - expect(prof.profLoc.osLoc).toBeDefined(); - expect(prof.profLoc.osLoc.length).toEqual(1); - expect(prof.profLoc.osLoc[0]).toEqual(path.join(homeDirPath, "profiles", prof.profType, prof.profName + ".yaml")); - expectedProfileNames = expectedProfileNames.filter(obj => obj !== prof.profName); - } - expect(actualDefaultProfiles).toEqual(expectedDefaultProfiles); - expect(expectedProfileNames.length).toEqual(0); - }); - - it("should return some profiles if a type is specified", async () => { - const length = 5; - const expectedName = "lpar1_zosmf"; - const expectedDefaultProfiles = 1; - const desiredProfType = "zosmf"; - let expectedProfileNames = ["lpar1_zosmf", "lpar2_zosmf", "lpar3_zosmf", "lpar4_zosmf", "lpar5_zosmf"]; - let actualDefaultProfiles = 0; - - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getAllProfiles(desiredProfType); - - expect(profAttrs.length).toEqual(length); - for (const prof of profAttrs) { - if (prof.isDefaultProfile) { - expect(prof.profName).toEqual(expectedName); - actualDefaultProfiles += 1; - } - expect(expectedProfileNames).toContain(prof.profName); - expect(profileTypes).toContain(prof.profType); - expect(prof.profLoc.locType).toEqual(ProfLocType.OLD_PROFILE); - expect(prof.profLoc.osLoc).toBeDefined(); - expect(prof.profLoc.osLoc.length).toEqual(1); - expect(prof.profLoc.osLoc[0]).toEqual(path.join(homeDirPath, "profiles", prof.profType, prof.profName + ".yaml")); - expectedProfileNames = expectedProfileNames.filter(obj => obj !== prof.profName); - } - expect(actualDefaultProfiles).toEqual(expectedDefaultProfiles); - expect(expectedProfileNames.length).toEqual(0); - }); - }); - - describe("mergeArgsForProfile", () => { - const profSchema: Partial = { - properties: { - host: { type: "string" }, - user: { - type: "string", - optionDefinition: { defaultValue: "admin" } - } as any, - password: { - type: "string", - optionDefinition: { defaultValue: "admin" } - } as any - } - }; - - const requiredProfSchema: Partial = { - properties: { - ...profSchema.properties, - protocol: { type: "string" } - }, - required: ["protocol"] - }; - - it("should find known args in simple service profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - delete (profInfo as any).mOldSchoolProfileDefaults.base; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs); - - const expectedArgs = [ - { argName: "host", dataType: "string" }, - { argName: "port", dataType: "number" }, - { argName: "user", dataType: "string" }, - { argName: "password", dataType: "string" }, - { argName: "rejectUnauthorized", dataType: "boolean" } - ]; - - expect(mergedArgs.knownArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.knownArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.secure || arg.argValue).toBeDefined(); - expect(arg.argLoc.locType).toBe(ProfLocType.OLD_PROFILE); - expect(arg.argLoc.osLoc[0]).toMatch(/lpar1_zosmf\.yaml$/); - } - }); - - it("should find known args in service and base profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - (profInfo as any).mOldSchoolProfileDefaults.base = "base_apiml"; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs); - - const expectedArgs = [ - { argName: "host", dataType: "string" }, - { argName: "port", dataType: "number" }, - { argName: "user", dataType: "string" }, - { argName: "password", dataType: "string" }, - { argName: "rejectUnauthorized", dataType: "boolean" }, - { argName: "tokenType", dataType: "string" }, - { argName: "tokenValue", dataType: "string" } - ]; - - expect(mergedArgs.knownArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.knownArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.secure || arg.argValue).toBeDefined(); - expect(arg.argLoc.locType).toBe(ProfLocType.OLD_PROFILE); - expect(arg.argLoc.osLoc[0]).toMatch(/(base_apiml|lpar1_zosmf)\.yaml$/); - } - }); - - it("should find known args defined with kebab case names", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getAllProfiles("zosmf").find(obj => obj.profName === "lpar2_zosmf"); - delete (profInfo as any).mOldSchoolProfileDefaults.base; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs as IProfAttrs); - - const expectedArgs = [ - { argName: "host", dataType: "string" }, - { argName: "port", dataType: "number" }, - { argName: "user", dataType: "string" }, - { argName: "password", dataType: "string" }, - { argName: "rejectUnauthorized", dataType: "boolean" } - ]; - - expect(mergedArgs.knownArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.knownArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.secure || arg.argValue).toBeDefined(); - expect(arg.argLoc.locType).toBe(ProfLocType.OLD_PROFILE); - expect(arg.argLoc.osLoc[0]).toMatch(/lpar2_zosmf\.yaml$/); - } - }); - - it("should list optional args missing in service profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getAllProfiles("zosmf").find(obj => obj.profName === "lpar3_zosmf"); - delete (profInfo as any).mOldSchoolProfileDefaults.base; - jest.spyOn(profInfo as any, "loadSchema").mockReturnValue(profSchema); - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs as IProfAttrs); - - const expectedArgs = [ - { argName: "user", dataType: "string", argValue: "admin" }, - { argName: "password", dataType: "string", argValue: "admin" } - ]; - - expect(mergedArgs.missingArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.missingArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.argLoc.locType).toBe(ProfLocType.DEFAULT); - expect(arg.argLoc.osLoc).toBeUndefined(); - } - }); - - it("should throw if there are required args missing in service profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - jest.spyOn(profInfo as any, "loadSchema").mockReturnValue(requiredProfSchema); - - let caughtError; - try { - profInfo.mergeArgsForProfile(profAttrs); - } catch (error) { - expect(error instanceof ProfInfoErr).toBe(true); - caughtError = error; - } - - expect(caughtError).toBeDefined(); - expect(caughtError.errorCode).toBe(ProfInfoErr.MISSING_REQ_PROP); - expect(caughtError.message).toContain("Missing required properties: protocol"); - }); - - it("should validate profile for missing args when schema exists", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getAllProfiles("zosmf").find(obj => obj.profName === "lpar3_zosmf"); - delete (profInfo as any).mOldSchoolProfileDefaults.base; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs as IProfAttrs); - - const expectedArgs = [ - { argName: "user", dataType: "string" }, - { argName: "password", dataType: "string" }, - { argName: "basePath", dataType: "string" } - ]; - - expect(mergedArgs.missingArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.missingArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.argLoc.locType).toBe(ProfLocType.DEFAULT); - expect(arg.argLoc.osLoc).toBeUndefined(); - } - }); - - it("should throw if schema fails to load", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - jest.spyOn(profInfo as any, "loadSchema").mockReturnValueOnce(null); - let caughtError; - - try { - profInfo.mergeArgsForProfile(profAttrs); - } catch (error) { - expect(error instanceof ProfInfoErr).toBe(true); - caughtError = error; - } - - expect(caughtError).toBeDefined(); - expect(caughtError.errorCode).toBe(ProfInfoErr.LOAD_SCHEMA_FAILED); - expect(caughtError.message).toContain("Failed to load schema for profile type zosmf"); - }); - - it("should throw if profile attributes are undefined", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("missing") as IProfAttrs; - let caughtError; - - try { - profInfo.mergeArgsForProfile(profAttrs); - } catch (error) { - expect(error instanceof ImperativeError).toBe(true); - caughtError = error; - } - - expect(caughtError).toBeDefined(); - expect(caughtError.message).toContain("Profile attributes must be defined"); - }); - }); - - describe("mergeArgsForProfileType", () => { - it("should find known args in base profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - jest.spyOn(profInfo as any, "loadSchema").mockReturnValueOnce({}); - const mergedArgs = profInfo.mergeArgsForProfileType("cics"); - - const expectedArgs = [ - { argName: "user", dataType: "string" }, - { argName: "password", dataType: "string" }, - { argName: "rejectUnauthorized", dataType: "boolean" } - ]; - - expect(mergedArgs.knownArgs.length).toBe(expectedArgs.length); - for (const [idx, arg] of mergedArgs.knownArgs.entries()) { - expect(arg).toMatchObject(expectedArgs[idx]); - expect(arg.argValue).toBeDefined(); - expect(arg.argLoc.locType).toBe(ProfLocType.OLD_PROFILE); - expect(arg.argLoc.osLoc[0]).toMatch(/base_for_userNm\.yaml$/); - } - }); - }); - - describe("loadAllSchemas", () => { - it("should load schema for profile type that does not exist", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - let caughtError; - - try { - (profInfo as any).loadAllSchemas(); - } catch (error) { - caughtError = error; - } - - expect(caughtError).toBeUndefined(); - expect((profInfo as any).mProfileSchemaCache.size).toBe(4); - }); - - it("should throw when schema file is invalid", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - jest.spyOn(ProfileIO, "readMetaFile").mockImplementationOnce(() => { - throw new Error("bad meta"); - }); - let caughtError; - - try { - (profInfo as any).loadAllSchemas(); - } catch (error) { - expect(error instanceof ProfInfoErr).toBe(true); - caughtError = error; - } - - expect(caughtError).toBeDefined(); - expect(caughtError.errorCode).toBe(ProfInfoErr.LOAD_SCHEMA_FAILED); - expect(caughtError.message).toContain("Failed to load schema for profile type"); - expect(caughtError.message).toContain("invalid meta file"); - }); - }); - - describe("updateProperty and updateKnownProperty", () => { - it("should succeed if the property is known", async () => { - const testProf = "lpar4_zosmf"; - const testHost = "lpar4.fakehost.com"; - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const before = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - await profInfo.updateProperty({ profileName: testProf, profileType: "zosmf", property: "host", value: "example.com" }); - const after = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - - expect(before.knownArgs.find(v => v.argName === "host").argValue).toEqual(testHost); - expect(after.knownArgs.find(v => v.argName === "host").argValue).toEqual("example.com"); - - await profInfo.updateProperty({ profileName: testProf, profileType: "zosmf", property: "host", value: testHost }); - const afterTests = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - expect(afterTests.knownArgs.find(v => v.argName === "host").argValue).toEqual(testHost); - }); - - it("should add a new property if it does not exist in the profile then remove it if undefined is specified", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const testProf = "lpar4_zosmf"; - const before = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - await profInfo.updateProperty({ profileName: testProf, profileType: "zosmf", property: "dummy", value: "example.com" }); - const after = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - - expect(before.knownArgs.find(v => v.argName === "dummy")).toBeUndefined(); - expect(after.knownArgs.find(v => v.argName === "dummy").argValue).toEqual("example.com"); - - await profInfo.updateProperty({ profileName: testProf, profileType: "zosmf", property: "dummy", value: undefined }); - const removed = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - expect(removed.knownArgs.find(v => v.argName === "dummy")).toBeUndefined(); - }); - }); - - describe("removeKnownProperty oldProfile tests", () => { - it("should remove property", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const testProf = "lpar4_zosmf"; - await profInfo.updateProperty({ profileName: testProf, profileType: "zosmf", property: "dummy", value: "example.com"}); - const afterUpdate = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - - await profInfo.removeKnownProperty({mergedArgs: afterUpdate, property: 'dummy'}); - const afterRemove = profInfo.mergeArgsForProfile((profInfo.getAllProfiles("zosmf").find(v => v.profName === testProf)) as IProfAttrs); - - expect(afterUpdate.knownArgs.find(v => v.argName === "dummy")?.argValue).toEqual("example.com"); - expect(afterRemove.knownArgs.find(v => v.argName === "dummy")).toBeUndefined(); - }); - }); - - describe("loadSecureArg", () => { - it("should load secure args from old school profiles", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs); - - const userArg = mergedArgs.knownArgs.find((arg) => arg.argName === "user"); - expect(userArg.argValue).toBeUndefined(); - expect(profInfo.loadSecureArg(userArg as IProfArgAttrs)).toBe("someUser"); - - const passwordArg = mergedArgs.knownArgs.find((arg) => arg.argName === "password"); - expect(passwordArg.argValue).toBeUndefined(); - expect(profInfo.loadSecureArg(passwordArg as IProfArgAttrs)).toBe("somePassword"); - }); - - it("should get secure values with mergeArgsForProfile:getSecureVals for old school profiles", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - const mergedArgs = profInfo.mergeArgsForProfile(profAttrs, { getSecureVals: true }); - - const userArg = mergedArgs.knownArgs.find((arg) => arg.argName === "user"); - expect(userArg.argValue).toBe("someUser"); - - const passwordArg = mergedArgs.knownArgs.find((arg) => arg.argName === "password"); - expect(passwordArg.argValue).toBe("somePassword"); - }); - }); - - describe("getOsLocInfo", () => { - it("should return undefined if no osLoc is present", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const prof = { profName: "test", profLoc: { locType: 0 }, profType: "test", isDefaultProfile: false }; - expect(profInfo.getOsLocInfo(prof)).toBeUndefined(); - expect(profInfo.getOsLocInfo({...prof, profLoc: {locType: 0, osLoc: []}})).toBeUndefined(); - }); - - it("should return basic osLoc information for a regular v1 profile", async () => { - const profInfo = createNewProfInfo(homeDirPath); - await profInfo.readProfilesFromDisk(); - const profAttrs = profInfo.getDefaultProfile("zosmf") as IProfAttrs; - const osLocInfo = profInfo.getOsLocInfo(profAttrs); - expect(osLocInfo).toBeDefined(); - expect(osLocInfo.length).toBe(1); - expect(osLocInfo[0].name).toEqual(profAttrs.profName); - expect(osLocInfo[0].path).toEqual(profAttrs.profLoc.osLoc[0]); - expect(osLocInfo[0].user).toBeUndefined(); - expect(osLocInfo[0].global).toBeUndefined(); - }); - }); -}); diff --git a/packages/imperative/src/config/__tests__/ProfileInfo.TeamConfig.unit.test.ts b/packages/imperative/src/config/__tests__/ProfileInfo.TeamConfig.unit.test.ts index d51937c64e..333b03cb94 100644 --- a/packages/imperative/src/config/__tests__/ProfileInfo.TeamConfig.unit.test.ts +++ b/packages/imperative/src/config/__tests__/ProfileInfo.TeamConfig.unit.test.ts @@ -10,6 +10,7 @@ */ import * as fs from "fs"; +import * as os from "os"; import * as path from "path"; import * as jsonfile from "jsonfile"; import * as lodash from "lodash"; @@ -24,6 +25,7 @@ import { ProfLocType } from "../src/doc/IProfLoc"; import { IProfileSchema } from "../../profiles"; import { AbstractSession, SessConstants } from "../../rest"; import { ConfigAutoStore } from "../src/ConfigAutoStore"; +import { EnvironmentalVariableSettings } from "../../imperative/src/env/EnvironmentalVariableSettings"; import { ImperativeConfig } from "../../utilities/src/ImperativeConfig"; import { ImperativeError } from "../../error"; import { IProfInfoUpdatePropOpts } from "../src/doc/IProfInfoUpdatePropOpts"; @@ -136,6 +138,76 @@ describe("TeamConfig ProfileInfo tests", () => { expect(profLoaded.profile.profLoc.jsonLoc).toBe(profAttrs.profLoc.jsonLoc); expect(profLoaded.profile.isDefaultProfile).toBe(profAttrs.isDefaultProfile); }); + + it("should detect that only V1 profiles exist", async () => { + // onlyV1ProfilesExist is a getter of a property, so mock the property + Object.defineProperty(ConfigUtils, "onlyV1ProfilesExist", { + configurable: true, + get: jest.fn(() => { + return true; + }) + }); + expect(ProfileInfo.onlyV1ProfilesExist).toBe(true); + }); + }); + + describe("getZoweDir", () => { + const expectedLoadedConfig = { + name: "zowe", + defaultHome: path.join("z", "zowe"), + envVariablePrefix: "ZOWE" + }; + let defaultHome: string; + let envReadSpy: any; + let homeDirSpy: any; + let loadedConfigOrig: any; + + beforeAll(() => { + loadedConfigOrig = ImperativeConfig.instance.loadedConfig; + }); + + beforeEach(() => { + envReadSpy = jest.spyOn(EnvironmentalVariableSettings, "read").mockReturnValue({ + cliHome: { value: null } + } as any); + homeDirSpy = jest.spyOn(os, "homedir").mockReturnValue(expectedLoadedConfig.defaultHome); + ImperativeConfig.instance.loadedConfig = undefined as any; + defaultHome = path.join(expectedLoadedConfig.defaultHome, ".zowe"); + }); + + afterAll(() => { + ImperativeConfig.instance.loadedConfig = loadedConfigOrig; + envReadSpy.mockRestore(); + homeDirSpy.mockRestore(); + }); + + it("should return the ENV cliHome even if loadedConfig is set in the process", () => { + jest.spyOn(EnvironmentalVariableSettings, "read").mockReturnValue({ cliHome: { value: "test" } } as any); + expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); + expect(ProfileInfo.getZoweDir()).toEqual("test"); + expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); + }); + + it("should return the defaultHome and set loadedConfig if undefined", () => { + expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); + expect(ProfileInfo.getZoweDir()).toEqual(defaultHome); + expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); + }); + + it("should return the defaultHome and reset loadedConfig if defaultHome changes", () => { + expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); + ImperativeConfig.instance.loadedConfig = { ...expectedLoadedConfig, defaultHome: "test" }; + expect(ImperativeConfig.instance.loadedConfig?.defaultHome).toEqual("test"); + expect(ProfileInfo.getZoweDir()).toEqual(defaultHome); + expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); + }); + + it("should return the defaultHome without resetting loadedConfig", () => { + expect(ImperativeConfig.instance.loadedConfig).toBeUndefined(); + ImperativeConfig.instance.loadedConfig = expectedLoadedConfig; + expect(ProfileInfo.getZoweDir()).toEqual(defaultHome); + expect(ImperativeConfig.instance.loadedConfig).toEqual({ ...expectedLoadedConfig, defaultHome }); + }); }); describe("createSession", () => { @@ -256,7 +328,6 @@ describe("TeamConfig ProfileInfo tests", () => { "getTeamConfig", "mergeArgsForProfile", "mergeArgsForProfileType", - "usingTeamConfig", "getOsLocInfo", "loadSecureArg" ]; @@ -279,7 +350,6 @@ describe("TeamConfig ProfileInfo tests", () => { const profInfo = createNewProfInfo(teamProjDir); await profInfo.readProfilesFromDisk(); - expect(profInfo.usingTeamConfig).toBe(true); const teamConfig: Config = profInfo.getTeamConfig(); expect(teamConfig).not.toBeNull(); expect(teamConfig.exists).toBe(true); @@ -292,7 +362,6 @@ describe("TeamConfig ProfileInfo tests", () => { const teamCfgOpts: IConfigOpts = { projectDir: teamProjDir }; await profInfo.readProfilesFromDisk(teamCfgOpts); - expect(profInfo.usingTeamConfig).toBe(true); const teamConfig: Config = profInfo.getTeamConfig(); expect(teamConfig).not.toBeNull(); expect(teamConfig.exists).toBe(true); @@ -906,6 +975,9 @@ describe("TeamConfig ProfileInfo tests", () => { describe("loadSchema", () => { it("should return null if schema is not found", () => { const profInfo = createNewProfInfo(teamProjDir); + profInfo["mLoadedConfig"] = { + mLayers: [] + } as any; let schema: IProfileSchema; let caughtError; diff --git a/packages/imperative/src/config/src/ConfigUtils.ts b/packages/imperative/src/config/src/ConfigUtils.ts index 6a1540fe7a..84dcbe7ae6 100644 --- a/packages/imperative/src/config/src/ConfigUtils.ts +++ b/packages/imperative/src/config/src/ConfigUtils.ts @@ -9,6 +9,9 @@ * */ +import { normalize as pathNormalize } from "path"; +import { existsSync as fsExistsSync } from "fs"; + import { CredentialManagerFactory } from "../../security"; import { ICommandArguments } from "../../cmd"; import { ImperativeConfig } from "../../utilities"; @@ -16,7 +19,7 @@ import { ImperativeError } from "../../error"; export class ConfigUtils { /** - * Coeerces string property value to a boolean or number type. + * Coerces string property value to a boolean or number type. * @param value String value * @param type Property type defined in the schema * @returns Boolean, number, or string @@ -65,6 +68,37 @@ export class ConfigUtils { return fullPath === partialPath || fullPath.startsWith(partialPath + ".profiles."); } + /** + * Returns an indicator that the user has no team configuration, but we + * detected the existence of old-school V1 profiles. We will not work with the + * V1 profiles. This function can let you tell a user that they are incorrectly + * trying to use V1 profiles. + * + * @returns True - Means there is *NO* team config *AND* we detected that a V1 profile exists. + * False otherwise. + */ + public static get onlyV1ProfilesExist(): boolean { + if (ImperativeConfig.instance.config?.exists) { + // we have a team config + return false; + } + + let v1ZosmfProfileFileNm: string; + try { + v1ZosmfProfileFileNm = pathNormalize(ImperativeConfig.instance.cliHome + "/profiles/zosmf/zosmf_meta.yaml"); + } catch (_thrownErr) { + // We failed to get the CLI home directory. So, we definitely have no V1 profiles. + return false; + } + + if (fsExistsSync(v1ZosmfProfileFileNm)) { + // we found V1 profiles + return true; + } + + return false; + } + /** * Form an error message for failures to securely save a value. * @param solution Text that our caller can supply for a solution. diff --git a/packages/imperative/src/config/src/ProfileCredentials.ts b/packages/imperative/src/config/src/ProfileCredentials.ts index 78e5f3e24c..384a99bad3 100644 --- a/packages/imperative/src/config/src/ProfileCredentials.ts +++ b/packages/imperative/src/config/src/ProfileCredentials.ts @@ -87,16 +87,14 @@ export class ProfileCredentials { } } - if (this.mProfileInfo.usingTeamConfig) { - await this.mProfileInfo.getTeamConfig().api.secure.load({ - load: ((key: string): Promise => { - return CredentialManagerFactory.manager.load(key, true); - }), - save: ((key: string, value: any): Promise => { - return CredentialManagerFactory.manager.save(key, value); - }) - }); - } + await this.mProfileInfo.getTeamConfig().api.secure.load({ + load: ((key: string): Promise => { + return CredentialManagerFactory.manager.load(key, true); + }), + save: ((key: string, value: any): Promise => { + return CredentialManagerFactory.manager.save(key, value); + }) + }); } /** @@ -104,7 +102,6 @@ export class ProfileCredentials { * @returns False if not using teamConfig or there are no secure fields */ private isTeamConfigSecure(): boolean { - if (!this.mProfileInfo.usingTeamConfig) return false; if (this.mProfileInfo.getTeamConfig().api.secure.secureFields().length === 0) return false; return true; } diff --git a/packages/imperative/src/config/src/ProfileInfo.ts b/packages/imperative/src/config/src/ProfileInfo.ts index 80c8b7b35b..395bc1ca16 100644 --- a/packages/imperative/src/config/src/ProfileInfo.ts +++ b/packages/imperative/src/config/src/ProfileInfo.ts @@ -33,10 +33,8 @@ import { Config } from "./Config"; import { ConfigSchema } from "./ConfigSchema"; import { IConfigOpts } from "./doc/IConfigOpts"; -// for old-school profile operations -import { AbstractProfileManager } from "../../profiles/src/abstract/AbstractProfileManager"; -import { CliProfileManager, ICommandProfileProperty, ICommandArguments } from "../../cmd"; -import { IProfileLoaded, IProfileProperty, IProfileSchema, ProfileIO } from "../../profiles"; +import { ICommandProfileProperty, ICommandArguments } from "../../cmd"; +import { IProfileLoaded, IProfileProperty, IProfileSchema } from "../../profiles"; // for imperative operations import { EnvironmentalVariableSettings } from "../../imperative/src/env/EnvironmentalVariableSettings"; @@ -126,9 +124,7 @@ import { Constants } from "../../constants"; * youRunSomeZosmfCommand(finalZosmfArgs); * } * - * // So you want to write to a config file? You must use your own - * // old-school techniques to write to old-school profiles. - * // You then use alternate logic for a team config. + * // So you want to write to a config file? * // You must use the Config API to write to a team configuration. * // See the Config class documentation for functions to set * // and save team config arguments. @@ -138,33 +134,24 @@ import { Constants } from "../../constants"; * youSetValuesToOverwrite( * zosmfMergedArgs.knownArgs, zosmfMergedArgs.missingArgs * ); - * if (profInfo.usingTeamConfig { - * let configObj: Config = profInfo.getTeamConfig(); - * youWriteArgValuesUsingConfigObj( - * configObj, yourZosmfArgsToWrite - * ); - * } else { - * youWriteOldSchoolProfiles(yourZosmfArgsToWrite); - * } + * + * let configObj: Config = profInfo.getTeamConfig(); + * youWriteArgValuesUsingConfigObj( + * configObj, yourZosmfArgsToWrite + * ); * */ export class ProfileInfo { private mLoadedConfig: Config = null; - private mUsingTeamConfig: boolean = false; private mAppName: string = null; private mImpLogger: Logger = null; - private mOldSchoolProfileCache: IProfileLoaded[] = null; - private mOldSchoolProfileRootDir: string = null; - private mOldSchoolProfileDefaults: { [key: string]: string } = null; - private mOldSchoolProfileTypes: string[]; private mOverrideWithEnv: boolean = false; private mHasValidSchema: boolean = false; /** * Cache of profile schema objects mapped by profile type and config path - * if applicable. Examples of map keys: + * if applicable. Example of map keys: * - For team config: "/root/.zowe/zowe.config.json:zosmf" - * - For old profiles: "zosmf" */ private mProfileSchemaCache: Map; private mCredentials: ProfileCredentials; @@ -197,8 +184,7 @@ export class ProfileInfo { } /** - * Update a given property regardless of whether it's found in the config file or not - * This function supports v1 profiles + * Update a given property in the config file. * @param options Set of options needed to update a given property */ public async updateProperty(options: IProfInfoUpdatePropOpts): Promise { @@ -212,7 +198,7 @@ export class ProfileInfo { } const mergedArgs = this.mergeArgsForProfile(desiredProfile, { getSecureVals: false }); - if (options.forceUpdate && this.usingTeamConfig) { + if (options.forceUpdate) { const knownProperty = mergedArgs.knownArgs.find((v => v.argName === options.property)); if (knownProperty != null) { const profPath = this.getTeamConfig().api.profiles.getProfilePathFromName(options.profileName); @@ -222,43 +208,34 @@ export class ProfileInfo { } } if (!(await this.updateKnownProperty({ ...options, mergedArgs, osLocInfo: this.getOsLocInfo(desiredProfile)?.[0] }))) { - if (this.usingTeamConfig) { - // Check to see if loadedConfig already contains the schema for the specified profile type - if (ImperativeConfig.instance.loadedConfig?.profiles?.find(p => p.type === options.profileType)?.schema == null || - ImperativeConfig.instance.loadedConfig?.baseProfile?.schema == null) { - - const loadedConfig = ImperativeConfig.instance.loadedConfig; - if (!loadedConfig.profiles) loadedConfig.profiles = []; - this.mProfileSchemaCache.forEach((value: IProfileSchema, key: string) => { - if (key.indexOf(":base") > 0 && loadedConfig.baseProfile == null) { - loadedConfig.baseProfile = { type: "base", schema: value }; - } else if (key.indexOf(":base") < 0 && !loadedConfig.profiles.find(p => p.type === key.split(":")[1])) { - // Add the schema corresponding to the given profile type - loadedConfig.profiles.push({ type: key.split(":")[1], schema: value }); - } - }); - ImperativeConfig.instance.loadedConfig = loadedConfig; - } - - await ConfigAutoStore._storeSessCfgProps({ - config: this.mLoadedConfig, - defaultBaseProfileName: this.mLoadedConfig?.mProperties.defaults.base, - sessCfg: { - [options.property === "host" ? "hostname" : options.property]: options.value - }, - propsToStore: [options.property], - profileName: options.profileName, - profileType: options.profileType, - setSecure: options.setSecure + // Check to see if loadedConfig already contains the schema for the specified profile type + if (ImperativeConfig.instance.loadedConfig?.profiles?.find(p => p.type === options.profileType)?.schema == null || + ImperativeConfig.instance.loadedConfig?.baseProfile?.schema == null) { + + const loadedConfig = ImperativeConfig.instance.loadedConfig; + if (!loadedConfig.profiles) loadedConfig.profiles = []; + this.mProfileSchemaCache.forEach((value: IProfileSchema, key: string) => { + if (key.indexOf(":base") > 0 && loadedConfig.baseProfile == null) { + loadedConfig.baseProfile = { type: "base", schema: value }; + } else if (key.indexOf(":base") < 0 && !loadedConfig.profiles.find(p => p.type === key.split(":")[1])) { + // Add the schema corresponding to the given profile type + loadedConfig.profiles.push({ type: key.split(":")[1], schema: value }); + } }); - } else { - const profMgr = new CliProfileManager({ profileRootDirectory: this.mOldSchoolProfileRootDir, type: options.profileType }); - // Add new property - await profMgr.update({ name: options.profileName, merge: true, profile: { [options.property]: options.value } }); - - // Update mOldSchoolProfileCache to get mergedArgs updated - this.mOldSchoolProfileCache.find(v => v.name === options.profileName).profile[options.property] = options.value; + ImperativeConfig.instance.loadedConfig = loadedConfig; } + + await ConfigAutoStore._storeSessCfgProps({ + config: this.mLoadedConfig, + defaultBaseProfileName: this.mLoadedConfig?.mProperties.defaults.base, + sessCfg: { + [options.property === "host" ? "hostname" : options.property]: options.value + }, + propsToStore: [options.property], + profileName: options.profileName, + profileType: options.profileType, + setSecure: options.setSecure + }); } } @@ -266,7 +243,6 @@ export class ProfileInfo { * Update a given property with the value provided. * This function only works for properties that can be found in the config files (including secure arrays). * If the property cannot be found, this function will resolve to false - * This function supports v1 profiles * @param options Set of options required to update a known property */ public async updateKnownProperty(options: IProfInfoUpdateKnownPropOpts): Promise { @@ -279,27 +255,6 @@ export class ProfileInfo { } switch (toUpdate.argLoc.locType) { - case ProfLocType.OLD_PROFILE: { - const filePath = toUpdate.argLoc.osLoc; - const profileName = ProfileIO.fileToProfileName(filePath[0], "." + filePath[0].split(".").slice(-1)[0]); - const profileType = filePath[0].substring(this.mOldSchoolProfileRootDir.length + 1).split(path.sep)[0]; - const profMgr = new CliProfileManager({ profileRootDirectory: this.mOldSchoolProfileRootDir, type: profileType }); - if (options.value !== undefined) { - await profMgr.update({ name: profileName, merge: true, profile: { [options.property]: options.value } }); - } else { - // Remove existing property (or don't do anything) - const oldProf = await profMgr.load({ name: profileName, failNotFound: false }); - if (oldProf && oldProf.profile && oldProf.profile[options.property]) { - delete oldProf.profile[options.property]; - await profMgr.save({ name: profileName, profile: oldProf.profile, overwrite: true, type: profileType }); - } - } - - // Update mOldSchoolProfileCache to get mergedArgs updated - const profile = this.mOldSchoolProfileCache.find(v => v.name === profileName); - if (profile != null) profile.profile[options.property] = options.value; // What should we do in the else case? - break; - } case ProfLocType.TEAM_CONFIG: { let oldLayer: IProfLocOsLocLayer; const layer = this.getTeamConfig().layerActive(); @@ -322,9 +277,13 @@ export class ProfileInfo { case ProfLocType.DEFAULT: return false; default: { + let msgText = "Invalid profile location type: "; + if (toUpdate.argLoc.locType == ProfLocType.OLD_PROFILE) { + msgText = "You can no longer write to V1 profiles. Location type = "; + } throw new ProfInfoErr({ errorCode: ProfInfoErr.INVALID_PROF_LOC_TYPE, - msg: "Invalid profile location type: " + toUpdate.argLoc.locType + msg: msgText + toUpdate.argLoc.locType }); } } @@ -380,52 +339,32 @@ export class ProfileInfo { const profiles: IProfAttrs[] = []; // Do we have team config profiles? - if (this.mUsingTeamConfig) { - const teamConfigProfs = this.mLoadedConfig.layerMerge({ maskSecure: true, excludeGlobalLayer: options?.excludeHomeDir }).profiles; - // Iterate over them - for (const prof in teamConfigProfs) { - // Check if the profile has a type - if (teamConfigProfs[prof].type && (profileType == null || teamConfigProfs[prof].type === profileType)) { - const jsonLocation: string = "profiles." + prof; - const teamOsLocation: string[] = this.findTeamOsLocation(jsonLocation, options?.excludeHomeDir); - const profAttrs: IProfAttrs = { - profName: prof, - profType: teamConfigProfs[prof].type, - isDefaultProfile: this.isDefaultTeamProfile(prof, profileType), - profLoc: { - locType: ProfLocType.TEAM_CONFIG, - osLoc: teamOsLocation, - jsonLoc: jsonLocation - } - }; - profiles.push(profAttrs); - } - // Check for subprofiles - if (teamConfigProfs[prof].profiles) { - // Get the subprofiles and add to profiles list - const jsonPath = "profiles." + prof; - const subProfiles: IProfAttrs[] = this.getTeamSubProfiles(prof, jsonPath, teamConfigProfs[prof].profiles, profileType); - for (const subProfile of subProfiles) { - profiles.push(subProfile); + const teamConfigProfs = this.mLoadedConfig.layerMerge({ maskSecure: true, excludeGlobalLayer: options?.excludeHomeDir }).profiles; + // Iterate over them + for (const prof in teamConfigProfs) { + // Check if the profile has a type + if (teamConfigProfs[prof].type && (profileType == null || teamConfigProfs[prof].type === profileType)) { + const jsonLocation: string = "profiles." + prof; + const teamOsLocation: string[] = this.findTeamOsLocation(jsonLocation, options?.excludeHomeDir); + const profAttrs: IProfAttrs = { + profName: prof, + profType: teamConfigProfs[prof].type, + isDefaultProfile: this.isDefaultTeamProfile(prof, profileType), + profLoc: { + locType: ProfLocType.TEAM_CONFIG, + osLoc: teamOsLocation, + jsonLoc: jsonLocation } - } + }; + profiles.push(profAttrs); } - } else { - for (const loadedProfile of this.mOldSchoolProfileCache) { - if (!profileType || profileType === loadedProfile.type) { - const typeDefaultProfile = this.getDefaultProfile(loadedProfile.type); - let defaultProfile = false; - if (typeDefaultProfile && typeDefaultProfile.profName === loadedProfile.name) { defaultProfile = true; } - profiles.push({ - profName: loadedProfile.name, - profType: loadedProfile.type, - isDefaultProfile: defaultProfile, - profLoc: { - locType: ProfLocType.OLD_PROFILE, - osLoc: [this.oldProfileFilePath(loadedProfile.type, loadedProfile.name)], - jsonLoc: undefined - } - }); + // Check for subprofiles + if (teamConfigProfs[prof].profiles) { + // Get the subprofiles and add to profiles list + const jsonPath = "profiles." + prof; + const subProfiles: IProfAttrs[] = this.getTeamSubProfiles(prof, jsonPath, teamConfigProfs[prof].profiles, profileType); + for (const subProfile of subProfiles) { + profiles.push(subProfile); } } } @@ -454,71 +393,30 @@ export class ProfileInfo { } }; - if (this.usingTeamConfig) { - // get default profile name from the team config - const configProperties = this.mLoadedConfig.mProperties; - if (!Object.prototype.hasOwnProperty.call(configProperties.defaults, profileType)) { - // no default exists for the requested type - this.mImpLogger.warn("Found no profile of type '" + - profileType + "' in team config." - ); - return null; - } - - // extract info from the underlying team config - const foundProfNm = configProperties.defaults[profileType]; - - // for a team config, we use the last node of the jsonLoc as the name - const foundJson = this.mLoadedConfig.api.profiles.getProfilePathFromName(foundProfNm); - const teamOsLocation: string[] = this.findTeamOsLocation(foundJson); - - // assign the required poperties to defaultProfile - defaultProfile.profName = foundProfNm; - defaultProfile.profLoc = { - locType: ProfLocType.TEAM_CONFIG, - osLoc: teamOsLocation, - jsonLoc: foundJson - }; - } else { - // get default profile from the old-school profiles - // first, some validation - if (!this.mOldSchoolProfileCache || this.mOldSchoolProfileCache.length === 0) { - // No old school profiles in the cache - warn and return null - this.mImpLogger.warn("Found no old-school profiles."); - return null; - } - if (!this.mOldSchoolProfileDefaults || Object.keys(this.mOldSchoolProfileDefaults).length === 0) { - // No old-school default profiles found - warn and return null - this.mImpLogger.warn("Found no default old-school profiles."); - return null; - } - - const profName = this.mOldSchoolProfileDefaults[profileType]; - if (!profName) { - // No old-school default profile of this type - warn and return null - this.mImpLogger.warn("Found no old-school profile for type '" + profileType + "'."); - return null; - } + // get default profile name from the team config + const configProperties = this.mLoadedConfig.mProperties; + if (!Object.prototype.hasOwnProperty.call(configProperties.defaults, profileType)) { + // no default exists for the requested type + this.mImpLogger.warn("Found no profile of type '" + + profileType + "' in team config." + ); + return null; + } - const loadedProfile = this.mOldSchoolProfileCache.find(obj => { - return obj.name === profName && obj.type === profileType; - }); - if (!loadedProfile) { - // Something really weird happened - this.mImpLogger.warn(`Profile with name '${profName}' was defined as the default profile for type '${profileType}' but was missing ` + - `from the cache.`); - return null; - } + // extract info from the underlying team config + const foundProfNm = configProperties.defaults[profileType]; - ImperativeExpect.toBeEqual(loadedProfile.type, profileType); + // for a team config, we use the last node of the jsonLoc as the name + const foundJson = this.mLoadedConfig.api.profiles.getProfilePathFromName(foundProfNm); + const teamOsLocation: string[] = this.findTeamOsLocation(foundJson); - // assign the required properties to defaultProfile - defaultProfile.profName = loadedProfile.name; - defaultProfile.profLoc = { - locType: ProfLocType.OLD_PROFILE, - osLoc: [this.oldProfileFilePath(profileType, loadedProfile.name)] - }; - } + // assign the required poperties to defaultProfile + defaultProfile.profName = foundProfNm; + defaultProfile.profLoc = { + locType: ProfLocType.TEAM_CONFIG, + osLoc: teamOsLocation, + jsonLoc: foundJson + }; return defaultProfile; } @@ -685,49 +583,6 @@ export class ProfileInfo { } } } - } else if (profile.profLoc.locType === ProfLocType.OLD_PROFILE) { - if (profile.profName != null) { - const serviceProfile = this.mOldSchoolProfileCache.find(obj => { - return obj.name === profile.profName && obj.type === profile.profType; - })?.profile; - if (serviceProfile != null) { - // Load args from service profile if one exists - for (const [propName, propVal] of Object.entries(serviceProfile)) { - // Skip undefined properties because they don't meet criteria for known args - if (propVal === undefined) continue; - mergedArgs.knownArgs.push({ - argName: CliUtils.getOptionFormat(propName).camelCase, - dataType: this.argDataType(typeof propVal), - argValue: propVal, - argLoc: this.argOldProfileLoc(profile.profName, profile.profType) - }); - } - } - } - - const baseProfileName = this.mOldSchoolProfileDefaults.base; - if (baseProfileName != null) { - // Load args from default base profile if one exists - const baseProfile = this.mOldSchoolProfileCache.find(obj => { - return obj.name === baseProfileName && obj.type === "base"; - })?.profile; - if (baseProfile != null) { - for (const [propName, propVal] of Object.entries(baseProfile)) { - // Skip undefined properties because they don't meet criteria for known args - if (propVal === undefined) continue; - const argName = CliUtils.getOptionFormat(propName).camelCase; - // Skip properties already loaded from service profile - if (!mergedArgs.knownArgs.find((arg) => arg.argName === argName)) { - mergedArgs.knownArgs.push({ - argName, - dataType: this.argDataType(typeof propVal), - argValue: propVal, - argLoc: this.argOldProfileLoc(baseProfileName, "base") - }); - } - } - } - } } else { throw new ProfInfoErr({ errorCode: ProfInfoErr.INVALID_PROF_LOC_TYPE, @@ -868,12 +723,42 @@ export class ProfileInfo { profName: null, profType: profileType, isDefaultProfile: false, - profLoc: { locType: this.mUsingTeamConfig ? ProfLocType.TEAM_CONFIG : ProfLocType.OLD_PROFILE } + profLoc: { locType: ProfLocType.TEAM_CONFIG } }, mergeOpts ); } + /** + * Retrieves the Zowe CLI home directory. In the situation Imperative has + * not initialized it we use a default value. + * @returns {string} - Returns the Zowe home directory + */ + public static getZoweDir(): string { + const defaultHome = path.join(os.homedir(), ".zowe"); + if (ImperativeConfig.instance.loadedConfig?.defaultHome !== defaultHome) { + ImperativeConfig.instance.loadedConfig = { + name: "zowe", + defaultHome, + envVariablePrefix: "ZOWE" + }; + } + return ImperativeConfig.instance.cliHome; + } + + /** + * Returns an indicator that the user has no team configuration, but we + * detected the existence of old-school V1 profiles. We will not work with the + * V1 profiles. This function can let you tell a user that they are incorrectly + * trying to use V1 profiles. + * + * @returns True - Means there is *NO* team config *AND* we detected that a V1 profile exists. + * False otherwise. + */ + public static get onlyV1ProfilesExist(): boolean { + return ConfigUtils.onlyV1ProfilesExist; + } + // _______________________________________________________________________ /** * Convert an IProfAttrs object into an IProfileLoaded objects @@ -935,17 +820,13 @@ export class ProfileInfo { // _______________________________________________________________________ /** - * Read either the new team configuration files (if any exist) or - * read the old-school profile files. + * Read the team configuration files (if any exist). * * @param teamCfgOpts - * The optional choices used when reading a team configuration. - * This parameter is ignored, if the end-user is using old-school - * profiles. + * The optional choices related to reading a team configuration. */ public async readProfilesFromDisk(teamCfgOpts?: IConfigOpts) { this.mLoadedConfig = await Config.load(this.mAppName, { homeDir: ImperativeConfig.instance.cliHome, ...teamCfgOpts }); - this.mUsingTeamConfig = this.mLoadedConfig.exists; try { if (this.mCredentials.isSecured) { @@ -959,58 +840,10 @@ export class ProfileInfo { }); } - if (!this.mUsingTeamConfig) { - // Clear out the values - this.mOldSchoolProfileCache = []; - this.mOldSchoolProfileDefaults = {}; - // Try to get profiles and types - this.mOldSchoolProfileRootDir = path.join(ImperativeConfig.instance.cliHome, "profiles"); - this.mOldSchoolProfileTypes = fs.existsSync(this.mOldSchoolProfileRootDir) ? - ProfileIO.getAllProfileDirectories(this.mOldSchoolProfileRootDir) : []; - // Iterate over the types - for (const profType of this.mOldSchoolProfileTypes) { - // Set up the profile manager and list of profile names - const profileManager = new CliProfileManager({ profileRootDirectory: this.mOldSchoolProfileRootDir, type: profType }); - const profileList = profileManager.getAllProfileNames(); - // Iterate over them all - for (const prof of profileList) { - // Load and add to the list - try { - const loadedProfile = await profileManager.load({ name: prof }); - this.mOldSchoolProfileCache.push(loadedProfile); - } catch (err) { - this.mImpLogger.warn(err.message); - } - } - - try { - const defaultProfile = await profileManager.load({ loadDefault: true }); - if (defaultProfile) { this.mOldSchoolProfileDefaults[profType] = defaultProfile.name; } - } catch (err) { - this.mImpLogger.warn(err.message); - } - } - } else { - this.mExtendersJson = ProfileInfo.readExtendersJsonFromDisk(); - } - + this.mExtendersJson = ProfileInfo.readExtendersJsonFromDisk(); this.loadAllSchemas(); } - // _______________________________________________________________________ - /** - * Returns an indicator of whether we are using a team configuration or - * old-school profiles. - * - * You must call ProfileInfo.readProfilesFromDisk() before calling this function. - * - * @returns True when we are using a team config. False means old-school profiles. - */ - public get usingTeamConfig(): boolean { - this.ensureReadFromDisk(); - return this.mUsingTeamConfig; - } - /** * Returns whether a valid schema was found (works for v1 and v2 configs) */ @@ -1061,18 +894,6 @@ export class ProfileInfo { } } break; - case ProfLocType.OLD_PROFILE: - if (arg.argLoc.osLoc?.length > 0) { - for (const loadedProfile of this.mOldSchoolProfileCache) { - const profilePath = this.oldProfileFilePath(loadedProfile.type, loadedProfile.name); - if (profilePath === arg.argLoc.osLoc[0]) { - // we found the loaded profile matching arg.osLoc - argValue = loadedProfile.profile[arg.argName]; - break; - } - } - } - break; default: // not stored securely if location is ENV or DEFAULT argValue = arg.argValue; } @@ -1187,66 +1008,46 @@ export class ProfileInfo { /** * Load any profile schema objects found on disk and cache them. For team * config, we check each config layer and load its schema JSON if there is - * one associated. For old school profiles, we load the meta YAML file for - * each profile type if it exists in the profile root directory. + * one associated. */ private loadAllSchemas(): void { this.mProfileSchemaCache = new Map(); - if (this.mUsingTeamConfig) { - // Load profile schemas for all layers - let lastSchema: { path: string, json: any } = { path: null, json: null }; - for (const layer of this.getTeamConfig().mLayers) { - if (layer.properties.$schema == null) continue; - const schemaUri = new url.URL(layer.properties.$schema, url.pathToFileURL(layer.path)); - if (schemaUri.protocol !== "file:") { - throw new ProfInfoErr({ - errorCode: ProfInfoErr.CANT_GET_SCHEMA_URL, - msg: `Failed to load schema for config file ${layer.path}: web URLs are not supported by ProfileInfo API` - }); - } - const schemaPath = url.fileURLToPath(schemaUri); - if (fs.existsSync(schemaPath)) { - try { - let schemaJson; - if (schemaPath !== lastSchema.path) { - schemaJson = jsonfile.readFileSync(schemaPath); - lastSchema = { path: schemaPath, json: schemaJson }; - } else { - schemaJson = lastSchema.json; - } - for (const { type, schema } of ConfigSchema.loadSchema(schemaJson)) { - this.mProfileSchemaCache.set(`${layer.path}:${type}`, schema); - } - } catch (error) { - throw new ProfInfoErr({ - errorCode: ProfInfoErr.LOAD_SCHEMA_FAILED, - msg: `Failed to load schema for config file ${layer.path}: invalid schema file`, - causeErrors: error - }); - } - } - } - this.mHasValidSchema = lastSchema.path != null; - } else { - // Load profile schemas from meta files in profile root dir - for (const type of this.mOldSchoolProfileTypes) { - const metaPath = this.oldProfileFilePath(type, type + AbstractProfileManager.META_FILE_SUFFIX); - if (fs.existsSync(metaPath)) { - this.mHasValidSchema = true; - try { - const metaProfile = ProfileIO.readMetaFile(metaPath); - this.mProfileSchemaCache.set(type, metaProfile.configuration.schema); - } catch (error) { - throw new ProfInfoErr({ - errorCode: ProfInfoErr.LOAD_SCHEMA_FAILED, - msg: `Failed to load schema for profile type ${type}: invalid meta file`, - causeErrors: error - }); + // Load profile schemas for all layers + let lastSchema: { path: string, json: any } = { path: null, json: null }; + for (const layer of this.getTeamConfig().mLayers) { + if (layer.properties.$schema == null) continue; + const schemaUri = new url.URL(layer.properties.$schema, url.pathToFileURL(layer.path)); + if (schemaUri.protocol !== "file:") { + throw new ProfInfoErr({ + errorCode: ProfInfoErr.CANT_GET_SCHEMA_URL, + msg: `Failed to load schema for config file ${layer.path}: web URLs are not supported by ProfileInfo API` + }); + } + const schemaPath = url.fileURLToPath(schemaUri); + if (fs.existsSync(schemaPath)) { + try { + let schemaJson; + if (schemaPath !== lastSchema.path) { + schemaJson = jsonfile.readFileSync(schemaPath); + lastSchema = { path: schemaPath, json: schemaJson }; + } else { + schemaJson = lastSchema.json; } + for (const { type, schema } of ConfigSchema.loadSchema(schemaJson)) { + this.mProfileSchemaCache.set(`${layer.path}:${type}`, schema); + } + } catch (error) { + throw new ProfInfoErr({ + errorCode: ProfInfoErr.LOAD_SCHEMA_FAILED, + msg: `Failed to load schema for config file ${layer.path}: invalid schema file`, + causeErrors: error + }); } } } + + this.mHasValidSchema = lastSchema.path != null; LoggerUtils.setProfileSchemas(this.mProfileSchemaCache); } @@ -1769,29 +1570,6 @@ export class ProfileInfo { }, foundInSecureArray]; } - /** - * Given a profile name and type, compute the profile location object - * containing OS location. - * @param profileName Name of an old school profile (e.g., LPAR1) - * @param profileType Type of an old school profile (e.g., zosmf) - */ - private argOldProfileLoc(profileName: string, profileType: string): IProfLoc { - return { - locType: ProfLocType.OLD_PROFILE, - osLoc: [this.oldProfileFilePath(profileType, profileName)] - }; - } - - /** - * Given a profile name and type, return the OS location of the associated - * YAML file. - * @param profileName Name of an old school profile (e.g., LPAR1) - * @param profileType Type of an old school profile (e.g., zosmf) - */ - private oldProfileFilePath(profileType: string, profileName: string) { - return path.join(this.mOldSchoolProfileRootDir, profileType, profileName + AbstractProfileManager.PROFILE_EXTENSION); - } - /** * Load the cached schema object for a profile type. Returns null if * schema is not found in the cache. @@ -1800,24 +1578,20 @@ export class ProfileInfo { private loadSchema(profile: IProfAttrs): IProfileSchema | null { let schemaMapKey: string; - if (profile.profLoc.locType === ProfLocType.TEAM_CONFIG) { - if (profile.profLoc.osLoc != null) { - // the profile exists, so use schema associated with its config JSON file - schemaMapKey = `${profile.profLoc.osLoc[0]}:${profile.profType}`; - } else { - // no profile exists, so loop through layers and use the first schema found - for (const layer of this.mLoadedConfig.mLayers) { - const tempKey = `${layer.path}:${profile.profType}`; - if (this.mProfileSchemaCache.has(tempKey)) { - schemaMapKey = tempKey; - break; - } + if (profile.profLoc.osLoc != null) { + // the profile exists, so use schema associated with its config JSON file + schemaMapKey = `${profile.profLoc.osLoc[0]}:${profile.profType}`; + } else { + // no profile exists, so loop through layers and use the first schema found + for (const layer of this.mLoadedConfig.mLayers) { + const tempKey = `${layer.path}:${profile.profType}`; + if (this.mProfileSchemaCache.has(tempKey)) { + schemaMapKey = tempKey; + break; } } - } else if (profile.profLoc.locType === ProfLocType.OLD_PROFILE) { - // for old school profiles, there is only one schema per profile type - schemaMapKey = profile.profType; } + if (schemaMapKey != null && this.mProfileSchemaCache.has(schemaMapKey)) { return this.mProfileSchemaCache.get(schemaMapKey); } diff --git a/packages/imperative/src/imperative/__tests__/ConfigValidator.unit.test.ts b/packages/imperative/src/imperative/__tests__/ConfigValidator.unit.test.ts index bbee4d5c4b..6bce5294c1 100644 --- a/packages/imperative/src/imperative/__tests__/ConfigValidator.unit.test.ts +++ b/packages/imperative/src/imperative/__tests__/ConfigValidator.unit.test.ts @@ -92,10 +92,11 @@ describe("Imperative should validate config provided by the consumer", () => { expect(false).toBe(true); } catch (e) { - expect(e.message) - .toContain("myProperty"); - expect(e.message) - .toContain("handler"); + expect(e.message).toContain( + 'Your Imperative profile configuration of type "myprofile" ' + + 'has the schema property "myProperty", which has multiple option definitions.' + ); + expect(e.message).toContain("Imperative is not be able to map multiple command line arguments to a single profile property."); } }); }); diff --git a/packages/imperative/src/imperative/__tests__/config/cmd/auto-init/BaseAutoInitHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/config/cmd/auto-init/BaseAutoInitHandler.unit.test.ts index 746297b4fa..f0fcdc2aae 100644 --- a/packages/imperative/src/imperative/__tests__/config/cmd/auto-init/BaseAutoInitHandler.unit.test.ts +++ b/packages/imperative/src/imperative/__tests__/config/cmd/auto-init/BaseAutoInitHandler.unit.test.ts @@ -33,11 +33,7 @@ const mockParams: IHandlerParameters = { }, arguments: {}, // To be defined by individual tests positionals: ["config", "auto-init"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName" - })) - } + profiles: {} } as any; describe("BaseAutoInitHandler", () => { diff --git a/packages/imperative/src/imperative/__tests__/config/cmd/report-env/EnvQuery.unit.test.ts b/packages/imperative/src/imperative/__tests__/config/cmd/report-env/EnvQuery.unit.test.ts index e1275fac91..568d8156db 100644 --- a/packages/imperative/src/imperative/__tests__/config/cmd/report-env/EnvQuery.unit.test.ts +++ b/packages/imperative/src/imperative/__tests__/config/cmd/report-env/EnvQuery.unit.test.ts @@ -9,12 +9,10 @@ * */ -import * as fs from "fs"; import * as os from "os"; import * as path from "path"; import { CommandResponse } from "../../../../../cmd/src/response/CommandResponse"; -import { IO } from "../../../../../io"; import { ImperativeConfig } from "../../../../../utilities"; import { PluginIssues } from "../../../../src/plugins/utilities/PluginIssues"; @@ -54,7 +52,7 @@ describe("Tests for EnvQuery module", () => { } }); - // set ImperativeConfig properties for a v2 config + // set ImperativeConfig properties for a team config impCfg = ImperativeConfig.instance; impCfg.rootCommandName = "zowe"; (impCfg.loadedConfig as any) = { daemonMode: false }; @@ -136,15 +134,6 @@ describe("Tests for EnvQuery module", () => { expect(itemObj.itemProbMsg).toBe(""); }); - it("should report the NVM version", async () => { - const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.NVM_VER); - if (!itemObj.itemVal.includes("nvm failed to display any output")) { - expect(itemObj.itemVal).toMatch(/[0-9]+.[0-9]+.[0-9]+/); - expect(itemObj.itemValMsg).toContain("Node Version Manager version ="); - } - expect(itemObj.itemProbMsg).toBe(""); - }); - it("should report the platform", async () => { const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.PLATFORM); expect(itemObj.itemVal === "win32" || itemObj.itemVal === "linux" || itemObj.itemVal === "darwin").toBeTruthy(); @@ -287,12 +276,10 @@ describe("Tests for EnvQuery module", () => { expect(itemObj.itemProbMsg).toBe("An unknown item ID was supplied = 999"); }); - it("should report Zowe V2 configuration info", async () => { - const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.ZOWE_CONFIG_TYPE); - expect(itemObj.itemVal).toContain("V2 Team Config"); + it("should report Zowe team configuration info", async () => { + const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.ZOWE_CONFIG_INFO); expect(itemObj.itemValMsg).toContain("Zowe daemon mode = off"); - expect(itemObj.itemValMsg).toContain("Zowe config type = V2 Team Config"); - expect(itemObj.itemValMsg).toContain("Team config files in effect:"); + expect(itemObj.itemValMsg).toContain("Zowe client config files in use:"); expect(itemObj.itemValMsg).toContain("fakeDir/zowe.config.json"); expect(itemObj.itemValMsg).toMatch(/base = +fakeBaseProfNm/); expect(itemObj.itemValMsg).toMatch(/zosmf = +fakeZosmfProfNm/); @@ -306,70 +293,12 @@ describe("Tests for EnvQuery module", () => { (impCfg.loadedConfig as any) = { daemonMode: true }; // return the values that we want from external commands - const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.ZOWE_CONFIG_TYPE); - expect(itemObj.itemVal).toContain("V2 Team Config"); + const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.ZOWE_CONFIG_INFO); expect(itemObj.itemValMsg).toContain("Zowe daemon mode = on"); expect(itemObj.itemValMsg).toMatch(/Default Zowe daemon executable directory = this_is_a_fake_cli_home_dir.bin/); expect(itemObj.itemProbMsg).toBe(""); }); - it("should report Zowe V1 configuration info", async () => { - // set ImperativeConfig properties to what we want - Object.defineProperty(impCfg, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - - const isDirSpy = jest.spyOn(IO as any, "isDir") - .mockReturnValue(true); - - const endvProfDir = "endevor"; - const tsoProfDir = "tso"; - const zosmfProfDir = "zosmf"; - const prof1 = "_prof_1"; - const prof2 = "_prof_2"; - const prof3 = "_prof_3"; - const readDirSyncSpy = jest.spyOn(fs, "readdirSync") - .mockReturnValueOnce([ - endvProfDir as unknown as fs.Dirent, - tsoProfDir as unknown as fs.Dirent, - zosmfProfDir as unknown as fs.Dirent - ]).mockReturnValueOnce([ - endvProfDir + prof1 as unknown as fs.Dirent, - endvProfDir + prof2 as unknown as fs.Dirent, - endvProfDir + prof3 as unknown as fs.Dirent - ]).mockReturnValueOnce([ - tsoProfDir + prof1 as unknown as fs.Dirent, - tsoProfDir + prof2 as unknown as fs.Dirent, - tsoProfDir + prof3 as unknown as fs.Dirent - ]).mockReturnValueOnce([ - zosmfProfDir + prof1 as unknown as fs.Dirent, - zosmfProfDir + prof2 as unknown as fs.Dirent, - zosmfProfDir + prof3 as unknown as fs.Dirent - ]); - - const itemObj: IGetItemVal = await EnvQuery.getEnvItemVal(ItemId.ZOWE_CONFIG_TYPE); - expect(itemObj.itemVal).toContain("V1 Profiles"); - expect(itemObj.itemValMsg).toContain("Zowe config type = V1 Profiles"); - expect(itemObj.itemValMsg).toContain("Available profiles:"); - expect(itemObj.itemValMsg).toContain(endvProfDir + " profiles:"); - expect(itemObj.itemValMsg).toContain(endvProfDir + prof1); - expect(itemObj.itemValMsg).toContain(endvProfDir + prof2); - expect(itemObj.itemValMsg).toContain(endvProfDir + prof3); - expect(itemObj.itemValMsg).toContain(tsoProfDir + " profiles:"); - expect(itemObj.itemValMsg).toContain(tsoProfDir + prof1); - expect(itemObj.itemValMsg).toContain(tsoProfDir + prof2); - expect(itemObj.itemValMsg).toContain(tsoProfDir + prof3); - expect(itemObj.itemValMsg).toContain(zosmfProfDir + " profiles:"); - expect(itemObj.itemValMsg).toContain(zosmfProfDir + prof1); - expect(itemObj.itemValMsg).toContain(zosmfProfDir + prof2); - expect(itemObj.itemValMsg).toContain(zosmfProfDir + prof3); - expect(itemObj.itemProbMsg).toBe(""); - }); }); // end getEnvItemVal function describe("test getCmdOutput", () => { diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/CreateProfilesHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/profiles/handlers/CreateProfilesHandler.unit.test.ts deleted file mode 100644 index f95db9d1b2..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/CreateProfilesHandler.unit.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../src/Imperative"); -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { IProfileLoaded } from "../../../../profiles"; -import { Imperative } from "../../../src/Imperative"; -import { ImperativeConfig } from "../../../../utilities"; - -const fakeProfileIoError = "Pretend a ProfileIO error occurred"; -const noMsgText = "No message text"; - -let errorText: string = noMsgText; -let logText: string = noMsgText; - -// "Mocked" version of the handler parameters for a create profile command -const createProfileParms: any = { - arguments: { - $0: "zowe", - _: ["profiles", "create", "zosmf-profiles", "newProfName"], - }, - response: { - data: { - setMessage: jest.fn((setMsgArgs) => { - // Nothing - }), - setObj: jest.fn((setObjArgs) => { - // Nothing - }) - }, - console: { - log: jest.fn((msgText) => { - logText = msgText; - }), - error: jest.fn((msgText) => { - errorText = msgText; - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fakeType" - } - } -}; - -// "Mocked" profiles -const FAKE_PROFS: IProfileLoaded[] = [ - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake1", - profile: { - name: "fake1", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - }, - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake", - profile: { - name: "fake2", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - } -]; - -const ProfileSaved = { - overwritten: true, - path: "this/is/a/great/path", - profile: { - type: "fakeProfileType" - } -}; - -// "Mocked" version of a crashings imperative API -const impApiMockedCrash = { - profileManager: (args: any) => { - throw new Error(fakeProfileIoError); - }, -}; - -// "Mocked" version of a successful imperative API - done here rather than a manual mock -const impApiMockedOk = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - return JSON.parse(JSON.stringify(FAKE_PROFS)); - }), - save: jest.fn(() => { - return ProfileSaved; - }), - }; - }, -}; - - -describe("create profile handler", () => { - - // Reset mocks for counters, etc. - beforeEach(() => { - errorText = noMsgText; - logText = noMsgText; - }); - - describe("successful operation", () => { - it("should create a profile", async () => { - /* Pretend that we have **no** team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedOk, configurable: true }); - const parms = Object.assign({}, ...[createProfileParms]); - const handlerReq = require("../../../src/profiles/handlers/CreateProfilesHandler"); - const handler = new handlerReq.default(); - - await handler.process(createProfileParms); - expect(errorText).toBe(noMsgText); - expect(logText).toContain("Review the created profile"); - }); - }); - - describe("error handling", () => { - it("should catch profileIO errors", async () => { - /* Pretend that we have a team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: true - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedCrash, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/CreateProfilesHandler"); - const handler = new handlerReq.default(); - await handler.process(createProfileParms); - expect(errorText).toContain("An error occurred trying to create a profile"); - expect(errorText).toContain(fakeProfileIoError); - }); - }); -}); diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/ListProfilesHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/profiles/handlers/ListProfilesHandler.unit.test.ts deleted file mode 100644 index e5fcc985b1..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/ListProfilesHandler.unit.test.ts +++ /dev/null @@ -1,243 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../src/Imperative"); -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { IProfileLoaded } from "../../../../profiles"; -import { Imperative } from "../../../src/Imperative"; -import { ImperativeConfig } from "../../../../utilities"; - -// "Mocked" profiles -const FAKE_PROFS: IProfileLoaded[] = [ - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake1", - profile: { - name: "fake1", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - }, - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake", - profile: { - name: "fake2", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - } -]; - -// "Mocked" version of the imperative API - done here rather than a manual mock -const MockedImperativeAPI = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - return JSON.parse(JSON.stringify(FAKE_PROFS)); - }) - }; - }, -}; - -// "Mocked" version to thrown an error -const MockedImperativeAPIError = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - throw new Error("ERROR!"); - }) - }; - }, -}; - -// "Mocked" version of the handler parameters -const HANDLER_PARAMETERS: any = { - arguments: { - $0: "zowe", - _: ["zos-jobs", "submit", "data-set"], - }, - response: { - data: { - setMessage: jest.fn((setMsgArgs) => { - // Nothing - }), - setObj: jest.fn((setObjArgs) => { - // Nothing - }) - }, - console: { - log: jest.fn((logs) => { - // Nothing - }), - error: jest.fn((errors) => { - // Nothing - }), - errorHeader: jest.fn(() => undefined) - }, - progress: { - startBar: jest.fn((parms) => undefined), - endBar: jest.fn(() => undefined) - }, - format: { - output: jest.fn((parms) => { - // Nothing - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fake" - } - }, - fullDefinition: undefined, - profiles: undefined -}; - -describe("list profiles handler", () => { - - // Reset mocks for counters, etc. - afterEach(() => { - jest.resetAllMocks(); - }); - - describe("error handling", () => { - it("should not transform errors from the profile manager", async () => { - // "Mock" with the object here - Object.defineProperty(Imperative, "api", { value: MockedImperativeAPIError, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/ListProfilesHandler"); - const handler = new handlerReq.default(); - const parms = Object.assign({}, ...[HANDLER_PARAMETERS]); - let error; - try { - await handler.process(parms); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - it("should catch profileIO errors", async () => { - let errorText: string = "not_yet_set"; - - // "Mocked" version of the handler parameters for a list profile command - const listProfileParms: any = { - arguments: { - $0: "zowe", - _: ["profiles", "list", "zosmf-profiles"], - }, - response: { - console: { - error: jest.fn((msgText) => { - errorText = msgText; - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fakeType" - } - } - }; - - /* Pretend that we have a team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: true - }; - }) - }); - - // pretend to crash when profileManager is created - const fakeProfileIoError = "Pretend a ProfileIO error occurred"; - Object.defineProperty(Imperative, "api", { - configurable: true, - value: { - profileManager: (args: any) => { - throw new Error(fakeProfileIoError); - } - } - }); - - const handlerReq = require("../../../src/profiles/handlers/ListProfilesHandler"); - const handler = new handlerReq.default(); - await handler.process(listProfileParms); - expect(errorText).toContain("An error occurred trying to list profiles"); - expect(errorText).toContain(fakeProfileIoError); - }); - }); - - describe("response", () => { - it("should load all profiles and display just the names", async () => { - // "Mock" with the object here - Object.defineProperty(Imperative, "api", { value: MockedImperativeAPI, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/ListProfilesHandler"); - const handler = new handlerReq.default(); - const parms = Object.assign({}, ...[HANDLER_PARAMETERS]); - parms.response.format.output = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - parms.response.data.setObj = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - parms.response.data.setMessage = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - await handler.process(parms); - expect(parms.response.data.setMessage).toHaveBeenCalledTimes(1); - expect(parms.response.data.setObj).toHaveBeenCalledTimes(1); - }); - - it("should load all profiles and display all contents", async () => { - // "Mock" with the object here - Object.defineProperty(Imperative, "api", { value: MockedImperativeAPI, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/ListProfilesHandler"); - const handler = new handlerReq.default(); - const parms = Object.assign({}, ...[HANDLER_PARAMETERS]); - parms.arguments.showContents = true; - parms.response.format.output = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - parms.response.data.setObj = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - parms.response.data.setMessage = jest.fn((args) => { - expect(args).toMatchSnapshot(); - }); - await handler.process(parms); - expect(parms.response.data.setMessage).toHaveBeenCalledTimes(1); - expect(parms.response.data.setObj).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/NewDeleteProfilesHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/profiles/handlers/NewDeleteProfilesHandler.unit.test.ts deleted file mode 100644 index 6801595838..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/NewDeleteProfilesHandler.unit.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../src/Imperative"); -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { IProfileLoaded } from "../../../../profiles"; -import { Imperative } from "../../../src/Imperative"; -import { ImperativeConfig } from "../../../../utilities"; - -const fakeProfileIoError = "Pretend a ProfileIO error occurred"; -const noMsgText = "No message text"; - -let errorText: string = noMsgText; -let logText: string = noMsgText; - -// "Mocked" version of the handler parameters for a delete profile command -const deleteProfileParms: any = { - arguments: { - $0: "zowe", - _: ["profiles", "delete", "zosmf-profile", "ProfileToDelete"], - }, - response: { - data: { - setMessage: jest.fn((setMsgArgs) => { - // Nothing - }), - setObj: jest.fn((setObjArgs) => { - // Nothing - }) - }, - console: { - log: jest.fn((msgText) => { - logText = msgText; - }), - error: jest.fn((msgText) => { - errorText = msgText; - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fakeType" - } - } -}; - -// "Mocked" profiles -const FAKE_PROFS: IProfileLoaded[] = [ - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake1", - profile: { - name: "fake1", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - }, - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake", - profile: { - name: "fake2", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - } -]; - -const ProfileDeleted = { - overwritten: true, - path: "this/is/a/great/path", - profile: { - type: "fakeProfileType" - } -}; - -// "Mocked" version of a crashing imperative API -const impApiMockedCrash = { - profileManager: (args: any) => { - throw new Error(fakeProfileIoError); - }, -}; - -// "Mocked" version of a successful imperative API - done here rather than a manual mock -const impApiMockedOk = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - return JSON.parse(JSON.stringify(FAKE_PROFS)); - }), - delete: jest.fn(() => { - return ProfileDeleted; - }), - }; - }, -}; - - -describe("delete profile handler", () => { - - // Reset mocks for counters, etc. - beforeEach(() => { - errorText = noMsgText; - logText = noMsgText; - }); - - describe("successful operation", () => { - it("should delete a profile", async () => { - /* Pretend that we have **no** team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedOk, configurable: true }); - const parms = Object.assign({}, ...[deleteProfileParms]); - const handlerReq = require("../../../src/profiles/handlers/NewDeleteProfilesHandler"); - const handler = new handlerReq.default(); - - await handler.process(deleteProfileParms); - expect(errorText).toBe(noMsgText); - expect(logText).toContain("was successfully deleted"); - }); - }); - - describe("error handling", () => { - it("should catch profileIO errors", async () => { - /* Pretend that we have a team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: true - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedCrash, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/NewDeleteProfilesHandler"); - const handler = new handlerReq.default(); - await handler.process(deleteProfileParms); - expect(errorText).toContain("An error occurred trying to delete a profile"); - expect(errorText).toContain(fakeProfileIoError); - }); - }); -}); diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/UpdateProfilesHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/profiles/handlers/UpdateProfilesHandler.unit.test.ts deleted file mode 100644 index 0032535b69..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/UpdateProfilesHandler.unit.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../src/Imperative"); -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { IProfileLoaded } from "../../../../profiles"; -import { Imperative } from "../../../src/Imperative"; -import { ImperativeConfig } from "../../../../utilities"; - -const fakeProfileIoError = "Pretend a ProfileIO error occurred"; -const noMsgText = "No message text"; - -let errorText: string = noMsgText; -let logText: string = noMsgText; - -// "Mocked" version of the handler parameters for an update profile command -const updateProfileParms: any = { - arguments: { - $0: "zowe", - _: ["profiles", "update", "zosmf-profiles", "newProfName"], - }, - response: { - data: { - setMessage: jest.fn((setMsgArgs) => { - // Nothing - }), - setObj: jest.fn((setObjArgs) => { - // Nothing - }) - }, - console: { - log: jest.fn((msgText) => { - logText = msgText; - }), - error: jest.fn((msgText) => { - errorText = msgText; - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fakeType" - } - } -}; - -// "Mocked" profiles -const FAKE_PROFS: IProfileLoaded[] = [ - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake1", - profile: { - name: "fake1", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - }, - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake", - profile: { - name: "fake2", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - } -]; - -const ProfileUpdated = { - overwritten: true, - path: "this/is/a/great/path", - profile: { - type: "fakeProfileType" - } -}; - -// "Mocked" version of a crashing imperative API -const impApiMockedCrash = { - profileManager: (args: any) => { - throw new Error(fakeProfileIoError); - }, -}; - -// "Mocked" version of a successful imperative API - done here rather than a manual mock -const impApiMockedOk = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - return JSON.parse(JSON.stringify(FAKE_PROFS)); - }), - update: jest.fn(() => { - return ProfileUpdated; - }), - }; - }, -}; - - -describe("update profile handler", () => { - - // Reset mocks for counters, etc. - beforeEach(() => { - errorText = noMsgText; - logText = noMsgText; - }); - - describe("successful operation", () => { - it("should update a profile", async () => { - /* Pretend that we have **no** team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedOk, configurable: true }); - const parms = Object.assign({}, ...[updateProfileParms]); - const handlerReq = require("../../../src/profiles/handlers/UpdateProfilesHandler"); - const handler = new handlerReq.default(); - - await handler.process(updateProfileParms); - expect(errorText).toBe(noMsgText); - expect(logText).toContain("Review the created profile"); - }); - }); - - describe("error handling", () => { - it("should catch profileIO errors", async () => { - /* Pretend that we have a team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: true - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedCrash, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/UpdateProfilesHandler"); - const handler = new handlerReq.default(); - await handler.process(updateProfileParms); - expect(errorText).toContain("An error occurred trying to update a profile"); - expect(errorText).toContain(fakeProfileIoError); - }); - }); -}); diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/ValidateProfileHandler.unit.test.ts b/packages/imperative/src/imperative/__tests__/profiles/handlers/ValidateProfileHandler.unit.test.ts deleted file mode 100644 index 406679f58c..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/ValidateProfileHandler.unit.test.ts +++ /dev/null @@ -1,202 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../../../src/Imperative"); -jest.mock("../../../../utilities/src/ImperativeConfig"); - -import { IProfileLoaded, ProfileValidator } from "../../../../profiles"; -import { ICommandProfileTypeConfiguration } from "../../../../cmd"; -import { Imperative } from "../../../src/Imperative"; -import { ImperativeConfig } from "../../../../utilities"; - -const fakeProfileIoError = "Pretend a ProfileIO error occurred"; -const noMsgText = "No message text"; - -let errorText: string = noMsgText; -let logText: string = noMsgText; - -// "Mocked" version of the handler parameters for a validate profile command -const validateProfileParms: any = { - arguments: { - $0: "zowe", - _: ["profiles", "validate", "endevor-profile", "endvProfName", "--print-plan-only"], - "print-plan-only": true - }, - response: { - data: { - setMessage: jest.fn((setMsgArgs) => { - // Nothing - }), - setObj: jest.fn((setObjArgs) => { - // Nothing - }) - }, - console: { - log: jest.fn((msgText) => { - logText = msgText; - }), - error: jest.fn((msgText) => { - errorText = msgText; - }) - } - }, - definition: { - customize: { - profileTypeIdentifier: "fakeType" - } - } -}; - -// "Mocked" profiles -const FAKE_PROFS: IProfileLoaded[] = [ - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake1", - profile: { - name: "fake1", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - }, - { - message: "loaded", - type: "fake", - failNotFound: true, - name: "fake", - profile: { - name: "fake2", - type: "fake", - data: "some data", - info: "some info", - nested: { - data: "nested data" - } - } - } -]; - -const ProfileLoaded = { - overwritten: true, - path: "this/is/a/great/path", - profile: { - type: "fakeProfileType" - } -}; - -// "Mocked" version of a crashing imperative API -const impApiMockedCrash = { - profileManager: (args: any) => { - throw new Error(fakeProfileIoError); - }, -}; - -// "Mocked" version of a successful imperative API - done here rather than a manual mock -const impApiMockedOk = { - profileManager: (args: any) => { - return { - getDefaultProfileName: jest.fn(() => { - return "fake1"; - }), - loadAll: jest.fn((loadArgs) => { - return JSON.parse(JSON.stringify(FAKE_PROFS)); - }), - load: jest.fn(() => { - return ProfileLoaded; - }), - }; - }, -}; - - -describe("validate endevor profile handler", () => { - - // Reset mocks for counters, etc. - beforeEach(() => { - errorText = noMsgText; - logText = noMsgText; - }); - - describe("successful operation", () => { - it("should validate a profile", async () => { - /* Pretend that we have **no** team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: false - }; - }) - }); - - const profConfig: ICommandProfileTypeConfiguration = { - type: "endevor", - schema: { - type: "endevor", - title: "some title", - description: "some description", - properties: { - type: { - type: "boolean" - }, - } - }, - validationPlanModule: "../../../../../__tests__/src/packages/imperative/plugins/test_cli/TestProfileValidationPlan1" - }; - Imperative.getProfileConfiguration = jest.fn(() => profConfig); - - // print-plan-only forced printing the plan, not validating - const printedPlanText = "Printed plan for profile validation"; - ProfileValidator.getTextDisplayForPlan = jest.fn(() => { - return printedPlanText; - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedOk, configurable: true }); - const parms = Object.assign({}, ...[validateProfileParms]); - const handlerReq = require("../../../src/profiles/handlers/ValidateProfileHandler"); - const handler = new handlerReq.default(); - - await handler.process(validateProfileParms); - expect(errorText).toBe(noMsgText); - expect(logText.toString()).toContain(printedPlanText); - }); - }); - - describe("error handling", () => { - it("should catch profileIO errors", async () => { - /* Pretend that we have a team config. - * config is a getter of a property, so mock we the property. - */ - Object.defineProperty(ImperativeConfig.instance, "config", { - configurable: true, - get: jest.fn(() => { - return { - exists: true - }; - }) - }); - - Object.defineProperty(Imperative, "api", { value: impApiMockedCrash, configurable: true }); - const handlerReq = require("../../../src/profiles/handlers/ValidateProfileHandler"); - const handler = new handlerReq.default(); - await handler.process(validateProfileParms); - expect(errorText).toContain("An error occurred trying to validate a profile"); - expect(errorText).toContain(fakeProfileIoError); - }); - }); -}); diff --git a/packages/imperative/src/imperative/__tests__/profiles/handlers/__snapshots__/ListProfilesHandler.unit.test.ts.snap b/packages/imperative/src/imperative/__tests__/profiles/handlers/__snapshots__/ListProfilesHandler.unit.test.ts.snap deleted file mode 100644 index 3dccde326d..0000000000 --- a/packages/imperative/src/imperative/__tests__/profiles/handlers/__snapshots__/ListProfilesHandler.unit.test.ts.snap +++ /dev/null @@ -1,144 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`list profiles handler error handling should not transform errors from the profile manager 1`] = `"ERROR!"`; - -exports[`list profiles handler response should load all profiles and display all contents 1`] = `"\\"2\\" profiles loaded for type \\"fake\\""`; - -exports[`list profiles handler response should load all profiles and display all contents 2`] = ` -Array [ - Object { - "failNotFound": true, - "message": "loaded", - "name": "fake1", - "profile": Object { - "data": "some data", - "info": "some info", - "name": "fake1", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "type": "fake", - }, - Object { - "failNotFound": true, - "message": "loaded", - "name": "fake", - "profile": Object { - "data": "some data", - "info": "some info", - "name": "fake2", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "type": "fake", - }, -] -`; - -exports[`list profiles handler response should load all profiles and display all contents 3`] = ` -Object { - "format": "object", - "output": Array [ - Object { - "contents": Object { - "data": "some data", - "info": "some info", - "name": "fake1", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "name": "fake1 (default) ", - }, - Object { - "contents": Object { - "data": "some data", - "info": "some info", - "name": "fake2", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "name": "fake", - }, - ], -} -`; - -exports[`list profiles handler response should load all profiles and display just the names 1`] = `"\\"2\\" profiles loaded for type \\"fake\\""`; - -exports[`list profiles handler response should load all profiles and display just the names 2`] = ` -Array [ - Object { - "failNotFound": true, - "message": "loaded", - "name": "fake1", - "profile": Object { - "data": "some data", - "info": "some info", - "name": "fake1", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "type": "fake", - }, - Object { - "failNotFound": true, - "message": "loaded", - "name": "fake", - "profile": Object { - "data": "some data", - "info": "some info", - "name": "fake2", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "type": "fake", - }, -] -`; - -exports[`list profiles handler response should load all profiles and display just the names 3`] = ` -Object { - "fields": Array [ - "name", - ], - "format": "list", - "output": Array [ - Object { - "contents": Object { - "data": "some data", - "info": "some info", - "name": "fake1", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "name": "fake1 (default) ", - }, - Object { - "contents": Object { - "data": "some data", - "info": "some info", - "name": "fake2", - "nested": Object { - "data": "nested data", - }, - "type": "fake", - }, - "name": "fake", - }, - ], -} -`; diff --git a/packages/imperative/src/imperative/src/ConfigurationValidator.ts b/packages/imperative/src/imperative/src/ConfigurationValidator.ts index e4054d6da3..fa6bceedd6 100644 --- a/packages/imperative/src/imperative/src/ConfigurationValidator.ts +++ b/packages/imperative/src/imperative/src/ConfigurationValidator.ts @@ -81,16 +81,14 @@ export class ConfigurationValidator { const property: ICommandProfileProperty = profileConfig.schema.properties[propertyName]; if (!isNullOrUndefined(property.optionDefinitions) && - property.optionDefinitions.length > 1 && - isNullOrUndefined(profileConfig.createProfileFromArgumentsHandler)) { + property.optionDefinitions.length > 1) + { throw new ImperativeError({ msg: TextUtils.formatMessage( - "Your Imperative profile configuration of type \"{{type}}\"" + - " has the schema property \"{{property}}\", which has multiple " + - "option definitions, but no handler for creating a profile from " + - "command line arguments. Imperative will not be able to determine " + - "how to map multiple command line arguments to a single profile property " + - "unless you provide a custom handler.", + "Your Imperative profile configuration of type \"{{type}}\" " + + "has the schema property \"{{property}}\", which has multiple " + + "option definitions. Imperative is not be able to " + + "map multiple command line arguments to a single profile property.", { type: profileConfig.type, property: propertyName diff --git a/packages/imperative/src/imperative/src/Imperative.ts b/packages/imperative/src/imperative/src/Imperative.ts index 5a1e36d0eb..d2a5a07edb 100644 --- a/packages/imperative/src/imperative/src/Imperative.ts +++ b/packages/imperative/src/imperative/src/Imperative.ts @@ -46,7 +46,6 @@ import { YargsDefiner } from "../../cmd/src/yargs/YargsDefiner"; import { IProfileTypeConfiguration } from "../../profiles/src/doc/config/IProfileTypeConfiguration"; import { ImperativeHelpGeneratorFactory } from "./help/ImperativeHelpGeneratorFactory"; import { OverridesLoader } from "./OverridesLoader"; -import { ImperativeProfileManagerFactory } from "./profiles/ImperativeProfileManagerFactory"; import { DefinitionTreeResolver } from "./DefinitionTreeResolver"; import { EnvironmentalVariableSettings } from "./env/EnvironmentalVariableSettings"; import { AppSettings } from "../../settings/src/AppSettings"; @@ -525,7 +524,6 @@ export class Imperative { preparedHostCliCmdTree, yargs, commandResponseParms, - new ImperativeProfileManagerFactory(this.api), this.mHelpGeneratorFactory, ImperativeConfig.instance.loadedConfig.experimentalCommandDescription, Imperative.rootCommandName, @@ -545,7 +543,6 @@ export class Imperative { Imperative.rootCommandName, Imperative.commandLine, ImperativeConfig.instance.envVariablePrefix, - new ImperativeProfileManagerFactory(this.api), this.mHelpGeneratorFactory, ImperativeConfig.instance.loadedConfig.experimentalCommandDescription, diff --git a/packages/imperative/src/imperative/src/api/ImperativeApi.ts b/packages/imperative/src/imperative/src/api/ImperativeApi.ts index 5011223b6c..358cbec56a 100644 --- a/packages/imperative/src/imperative/src/api/ImperativeApi.ts +++ b/packages/imperative/src/imperative/src/api/ImperativeApi.ts @@ -12,7 +12,6 @@ import { IImperativeConfig } from "../doc/IImperativeConfig"; import { IImperativeApi } from "./doc/IImperativeApi"; import { Logger } from "../../../logger"; -import { ProfileUtils } from "../../../profiles"; import { CliProfileManager } from "../../../cmd"; export class ImperativeApi { @@ -68,12 +67,12 @@ export class ImperativeApi { /** * Return an instance of a profile manager for a given profile type * See ProfileManager.ts for more details + * @internal */ public profileManager(type: string): CliProfileManager { return new CliProfileManager({ type, typeConfigurations: this.mConfig.profiles, - profileRootDirectory: ProfileUtils.constructProfilesRootDirectory(this.mHome), logger: this.imperativeLogger, productDisplayName: this.mConfig.productDisplayName }); diff --git a/packages/imperative/src/imperative/src/auth/__tests__/BaseAuthHandler.unit.test.ts b/packages/imperative/src/imperative/src/auth/__tests__/BaseAuthHandler.unit.test.ts index 547a55694e..22f4c344b2 100644 --- a/packages/imperative/src/imperative/src/auth/__tests__/BaseAuthHandler.unit.test.ts +++ b/packages/imperative/src/imperative/src/auth/__tests__/BaseAuthHandler.unit.test.ts @@ -10,26 +10,77 @@ */ import { IHandlerParameters } from "../../../../cmd"; -import { Imperative } from "../../Imperative"; +import { ConnectionPropsForSessCfg } from "../../../.."; import { ImperativeConfig } from "../../../.."; import FakeAuthHandler from "./__data__/FakeAuthHandler"; describe("BaseAuthHandler", () => { - const mockSaveProfile = jest.fn(); - const mockUpdateProfile = jest.fn(); + const configSaveMock = jest.fn(); + let teamCfgExistsMock = jest.fn(() => true); + let profileExistsMock = jest.fn(() => true); beforeAll(() => { - Object.defineProperty(Imperative, "api", { - get: () => ({ - profileManager: (profType: string) => ({ - save: mockSaveProfile, - update: mockUpdateProfile - }) - }) - }); + // we do not want to call the real addPropsOrPrompt + ConnectionPropsForSessCfg.addPropsOrPrompt = jest.fn((): any => ({ + hostname: "connHostNm", + port: 5678, + user: "connUser", + password: "connPassword" + })); + + // we do not want to use the real ImperativeConfig Object.defineProperty(ImperativeConfig, "instance", { get: () => ({ - config: { exists: false } + cliHome: (): string => "/fake/cli/home/path", + envVariablePrefix: (): string => "FAKE_ZOWE_CLI_PREFIX", + config: { + exists: teamCfgExistsMock, + set: (): any => null, + save: configSaveMock, + properties: { + defaults: { "zosmf": "fakeProfNm" }, + profiles: { + fakeProfNm: { + type: "zosmf", + host: "fakeHostNm", + port: 1234 + } + } + }, + api: { + secure: { + loadFailed: false, + securePropsForProfile: (): any => [] + }, + profiles: { + get: () => ({ + fakeProfNm: { + type: "zosmf", + host: "fakeHostNm", + port: 1234 + } + }), + set: jest.fn(), + defaultSet: jest.fn(), + exists: profileExistsMock, + getProfilePathFromName: () => "fake/path" + }, + layers: { + get: () => ({ + path: "fake/path", + exists: true, + properties: {}, + global: true, + user: false + }), + find: () => ({ + user: false, + global: true + }), + activate: (): any => null + } + } + } }) }); }); @@ -51,13 +102,13 @@ describe("BaseAuthHandler", () => { password: "fakePass" }, positionals: ["auth", "login"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName" - })) - } + profiles: {} } as any; + // report that we have a team config and a profile + teamCfgExistsMock = jest.fn(() => true); + profileExistsMock = jest.fn(() => true); + const doLoginSpy = jest.spyOn(handler as any, "doLogin"); let caughtError; @@ -69,7 +120,7 @@ describe("BaseAuthHandler", () => { expect(caughtError).toBeUndefined(); expect(doLoginSpy).toHaveBeenCalledTimes(1); - expect(mockUpdateProfile).toHaveBeenCalledTimes(1); + expect(configSaveMock).toHaveBeenCalledTimes(1); }); it("should process login successfully and create profile", async () => { @@ -85,12 +136,16 @@ describe("BaseAuthHandler", () => { user: "fakeUser", password: "fakePass" }, - positionals: ["auth", "login"], - profiles: { - getMeta: jest.fn() - } + positionals: ["auth", "login"] } as any; + // report user and password are in our secure properties + ImperativeConfig.instance.config.api.secure.securePropsForProfile = (): any => ["user", "password"]; + + // report that we have no team config and no profile + teamCfgExistsMock = jest.fn(() => false); + profileExistsMock = jest.fn(() => false); + const doLoginSpy = jest.spyOn(handler as any, "doLogin"); let caughtError; @@ -103,7 +158,7 @@ describe("BaseAuthHandler", () => { expect(caughtError).toBeUndefined(); expect(doLoginSpy).toHaveBeenCalledTimes(1); expect(params.response.console.prompt).toHaveBeenCalledTimes(1); - expect(mockSaveProfile).toHaveBeenCalledTimes(1); + expect(configSaveMock).toHaveBeenCalledTimes(1); }); it("should process login successfully without creating profile on timeout", async () => { @@ -122,12 +177,13 @@ describe("BaseAuthHandler", () => { user: "fakeUser", password: "fakePass" }, - positionals: ["auth", "login"], - profiles: { - getMeta: jest.fn() - } + positionals: ["auth", "login"] } as any; + // report that we have no team config and no profile + teamCfgExistsMock = jest.fn(() => false); + profileExistsMock = jest.fn(() => false); + const doLoginSpy = jest.spyOn(handler as any, "doLogin"); let caughtError; @@ -140,7 +196,7 @@ describe("BaseAuthHandler", () => { expect(caughtError).toBeUndefined(); expect(doLoginSpy).toHaveBeenCalledTimes(1); expect(params.response.console.prompt).toHaveBeenCalledTimes(1); - expect(mockSaveProfile).toHaveBeenCalledTimes(0); + expect(configSaveMock).toHaveBeenCalledTimes(0); }); it("should process logout successfully", async () => { @@ -160,19 +216,14 @@ describe("BaseAuthHandler", () => { user: "fakeUser", password: "fakePass" }, - positionals: ["auth", "logout"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName", - profile: { - tokenValue: "fakeToken" - } - })) - } + positionals: ["auth", "logout"] } as any; + // report that we have a team config and a profile + teamCfgExistsMock = jest.fn(() => true); + profileExistsMock = jest.fn(() => true); + const doLogoutSpy = jest.spyOn(handler as any, "doLogout"); - const processLogoutOldSpy = jest.spyOn(handler as any, "processLogoutOld"); let caughtError; try { @@ -183,18 +234,32 @@ describe("BaseAuthHandler", () => { expect(caughtError).toBeUndefined(); expect(doLogoutSpy).toHaveBeenCalledTimes(1); - expect(processLogoutOldSpy).toHaveBeenCalledTimes(1); expect(params.arguments.tokenType).toEqual(handler.mDefaultTokenType); expect(params.arguments.user).toBeUndefined(); expect(params.arguments.password).toBeUndefined(); + expect(configSaveMock).toHaveBeenCalledTimes(0); + }); - it("should process logout successfully even when tokenValue is not provided", async () => { + it("should not logout when tokenValue is not provided", async () => { + let errMsg: string = ""; + let exitCode: number = 0; const handler = new FakeAuthHandler(); const params: IHandlerParameters = { response: { console: { - log: jest.fn() + log: jest.fn(), + errorHeader: jest.fn((_errMsg) => { + errMsg += _errMsg + "\n"; + }), + error: jest.fn((_errMsg) => { + errMsg += _errMsg + "\n"; + }), + }, + data: { + setExitCode: jest.fn((_exitCode) => { + exitCode = _exitCode; + }) } }, arguments: { @@ -203,16 +268,14 @@ describe("BaseAuthHandler", () => { tokenType: handler.mDefaultTokenType, tokenValue: null, }, - positionals: ["auth", "logout"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName" - })) - } + positionals: ["auth", "logout"] } as any; + // report that we have a team config and a profile + teamCfgExistsMock = jest.fn(() => true); + profileExistsMock = jest.fn(() => true); + const doLogoutSpy = jest.spyOn(handler as any, "doLogout"); - const processLogoutOldSpy = jest.spyOn(handler as any, "processLogoutOld"); let caughtError; try { @@ -223,7 +286,9 @@ describe("BaseAuthHandler", () => { expect(caughtError).toBeUndefined(); expect(doLogoutSpy).toHaveBeenCalledTimes(0); - expect(processLogoutOldSpy).toHaveBeenCalledTimes(1); + expect(errMsg).toContain("Token was not provided, so can't log out"); + expect(errMsg).toContain("You need to authenticate first using `zowe auth login`"); + expect(exitCode).toEqual(1); }); it("should fail to process invalid action name", async () => { @@ -235,12 +300,7 @@ describe("BaseAuthHandler", () => { } }, arguments: {}, - positionals: ["auth", "invalid"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName" - })) - } + positionals: ["auth", "invalid"] } as any; let caughtError; @@ -268,12 +328,7 @@ describe("BaseAuthHandler", () => { user: "fakeUser", password: "fakePass" }, - positionals: ["auth", "login"], - profiles: { - getMeta: jest.fn(() => ({ - name: "fakeName" - })) - } + positionals: ["auth", "login"] } as any; const doLoginSpy = jest.spyOn(handler as any, "doLogin").mockResolvedValue(null); diff --git a/packages/imperative/src/imperative/src/auth/handlers/BaseAuthHandler.ts b/packages/imperative/src/imperative/src/auth/handlers/BaseAuthHandler.ts index 1d90405b21..62eefad738 100644 --- a/packages/imperative/src/imperative/src/auth/handlers/BaseAuthHandler.ts +++ b/packages/imperative/src/imperative/src/auth/handlers/BaseAuthHandler.ts @@ -15,12 +15,9 @@ import { ConnectionPropsForSessCfg, ISession, RestConstants, - SessConstants, Session } from "../../../../rest"; -import { Imperative } from "../../Imperative"; import { IImperativeError, ImperativeError } from "../../../../error"; -import { ISaveProfileFromCliArgs } from "../../../../profiles"; import { ImperativeConfig } from "../../../../utilities"; import { ConfigUtils } from "../../../../config/src/ConfigUtils"; import { AbstractAuthHandler } from "./AbstractAuthHandler"; @@ -98,9 +95,6 @@ export abstract class BaseAuthHandler extends AbstractAuthHandler { if (params.arguments.showToken) { // show token instead of updating profile this.showToken(params.response, tokenValue); - } else if (!ImperativeConfig.instance.config.exists) { - // process login for old school profiles - await this.processLoginOld(params, tokenValue); } else if (ImperativeConfig.instance.config.api.secure.loadFailed) { throw ConfigUtils.secureSaveError(`Instead of secure storage, ` + `rerun this command with the "--show-token" flag to print the token to console. ` + @@ -217,146 +211,45 @@ export abstract class BaseAuthHandler extends AbstractAuthHandler { } } - if (!ImperativeConfig.instance.config.exists) { - if (sessCfgWithCreds.tokenValue == null) { - // Provide dummy token information to prevent multiple V1 logout operations from failing - sessCfgWithCreds.type = SessConstants.AUTH_TYPE_TOKEN; - sessCfgWithCreds.tokenType = this.mDefaultTokenType; - sessCfgWithCreds.tokenValue = SessConstants.AUTH_TYPE_TOKEN; - } - this.mSession = new Session(sessCfgWithCreds); - await this.processLogoutOld(params); - } else { - const config = ImperativeConfig.instance.config; - const profileName = this.getBaseProfileName(params); - const profileProps = config.api.profiles.get(profileName, false); - let profileWithToken: string = null; - - let noDeleteReason = ""; - // If you specified a token on the command line, then don't delete the one in the profile if it doesn't match - if (Object.keys(profileProps).length > 0 && profileProps.tokenType != null && profileProps.tokenValue != null && - profileProps.tokenType === params.arguments.tokenType && profileProps.tokenValue === params.arguments.tokenValue) { - const profilePath = config.api.profiles.getProfilePathFromName(profileName); - config.delete(`${profilePath}.properties.tokenType`); - config.delete(`${profilePath}.properties.tokenValue`); - - await config.save(); - profileWithToken = profileName; - } else { - if (Object.keys(profileProps).length === 0) noDeleteReason = "Empty profile was provided."; - else if (profileProps.tokenType == null) noDeleteReason = "Token type was not provided."; - else if (profileProps.tokenValue == null) noDeleteReason = "Token value was not provided."; - else if (profileProps.tokenType !== params.arguments.tokenType) - noDeleteReason = "Token type does not match the authentication service"; - else if (profileProps.tokenValue !== params.arguments.tokenValue) - noDeleteReason = "Token value does not match the securely stored value"; - } - - if (params.arguments.tokenValue != null) { - let logoutMessage = "Logout successful. The authentication token has been revoked."; - if (logoutError?.errorCode === RestConstants.HTTP_STATUS_401.toString()) { - logoutMessage = "Token is not valid or expired."; - } - logoutMessage += `\nToken was${profileWithToken == null ? " not" : ""} removed from ` + - `your '${profileName}' ${this.mProfileType} profile.`; - logoutMessage += `${!noDeleteReason ? "" : "\nReason: " + noDeleteReason}`; - params.response.console.log(logoutMessage); - } else { - params.response.console.errorHeader("Command Error"); - params.response.console.error("Token was not provided, so can't log out."+ - "\nYou need to authenticate first using `zowe auth login`."); - params.response.data.setExitCode(1); - } - } - } - - /* Methods for old-school profiles below */ - private async processLoginOld(params: IHandlerParameters, tokenValue: string) { - const loadedProfile = params.profiles.getMeta(this.mProfileType, false); + const config = ImperativeConfig.instance.config; + const profileName = this.getBaseProfileName(params); + const profileProps = config.api.profiles.get(profileName, false); let profileWithToken: string = null; - if (loadedProfile != null && loadedProfile.name != null) { - await Imperative.api.profileManager(this.mProfileType).update({ - name: loadedProfile.name, - args: { - "token-type": this.mSession.ISession.tokenType, - "token-value": tokenValue - }, - merge: true - }); - profileWithToken = loadedProfile.name; - } else { - - // Do not store non-profile arguments, user, or password. Set param arguments for prompted values from session. - - const copyArgs = {...params.arguments}; - copyArgs.createProfile = undefined; - copyArgs.showToken = undefined; - copyArgs.user = undefined; - copyArgs.password = undefined; - - copyArgs.host = this.mSession.ISession.hostname; - copyArgs.port = this.mSession.ISession.port; - - copyArgs.tokenType = this.mSession.ISession.tokenType; - copyArgs["token-type"] = this.mSession.ISession.tokenType; - - copyArgs.tokenValue = tokenValue; - copyArgs["token-value"] = tokenValue; - - const createParms: ISaveProfileFromCliArgs = { - name: "default", - type: this.mProfileType, - args: copyArgs, - overwrite: false, - profile: {} - }; + let noDeleteReason = ""; + // If you specified a token on the command line, then don't delete the one in the profile if it doesn't match + if (Object.keys(profileProps).length > 0 && profileProps.tokenType != null && profileProps.tokenValue != null && + profileProps.tokenType === params.arguments.tokenType && profileProps.tokenValue === params.arguments.tokenValue) { + const profilePath = config.api.profiles.getProfilePathFromName(profileName); + config.delete(`${profilePath}.properties.tokenType`); + config.delete(`${profilePath}.properties.tokenValue`); - if (await this.promptForBaseProfile(params, createParms.name)) { - await Imperative.api.profileManager(this.mProfileType).save(createParms); - profileWithToken = createParms.name; - } else { - this.showToken(params.response, tokenValue); - } + await config.save(); + profileWithToken = profileName; + } else { + if (Object.keys(profileProps).length === 0) noDeleteReason = "Empty profile was provided."; + else if (profileProps.tokenType == null) noDeleteReason = "Token type was not provided."; + else if (profileProps.tokenValue == null) noDeleteReason = "Token value was not provided."; + else if (profileProps.tokenType !== params.arguments.tokenType) + noDeleteReason = "Token type does not match the authentication service"; + else if (profileProps.tokenValue !== params.arguments.tokenValue) + noDeleteReason = "Token value does not match the securely stored value"; } - if (profileWithToken != null) { - params.response.console.log(`\n` + - `Login successful. The authentication token is stored in the '${profileWithToken}' ` + - `${this.mProfileType} profile for future use. To revoke this token and remove it from your profile, review the ` + - `'zowe auth logout' command.`); - } - } - - private async processLogoutOld(params: IHandlerParameters) { - const loadedProfile = params.profiles.getMeta(this.mProfileType, false); - - // If you specified a token on the command line, then don't delete the one in the profile if it doesn't match - let profileWithToken: string = null; - if (loadedProfile != null && - loadedProfile.name != null && - loadedProfile.profile != null && - loadedProfile.profile.tokenValue != null && - params.arguments.tokenValue === loadedProfile.profile.tokenValue) { - await Imperative.api.profileManager(this.mProfileType).save({ - name: loadedProfile.name, - type: loadedProfile.type, - overwrite: true, - profile: { - ...loadedProfile.profile, - tokenType: undefined, - tokenValue: undefined - } - }); - profileWithToken = loadedProfile.name; + if (params.arguments.tokenValue != null) { + let logoutMessage = "Logout successful. The authentication token has been revoked."; + if (logoutError?.errorCode === RestConstants.HTTP_STATUS_401.toString()) { + logoutMessage = "Token is not valid or expired."; + } + logoutMessage += `\nToken was${profileWithToken == null ? " not" : ""} removed from ` + + `your '${profileName}' ${this.mProfileType} profile.`; + logoutMessage += `${!noDeleteReason ? "" : "\nReason: " + noDeleteReason}`; + params.response.console.log(logoutMessage); + } else { + params.response.console.errorHeader("Command Error"); + params.response.console.error("Token was not provided, so can't log out."+ + "\nYou need to authenticate first using `zowe auth login`."); + params.response.data.setExitCode(1); } - - this.mSession.ISession.type = SessConstants.AUTH_TYPE_BASIC; - this.mSession.ISession.tokenType = undefined; - this.mSession.ISession.tokenValue = undefined; - - params.response.console.log("Logout successful. The authentication token has been revoked" + - (profileWithToken != null ? ` and removed from your '${profileWithToken}' ${this.mProfileType} profile` : "") + - "."); } } diff --git a/packages/imperative/src/imperative/src/config/cmd/convert-profiles/convert-profiles.handler.ts b/packages/imperative/src/imperative/src/config/cmd/convert-profiles/convert-profiles.handler.ts index 966ff24249..771e50d083 100644 --- a/packages/imperative/src/imperative/src/config/cmd/convert-profiles/convert-profiles.handler.ts +++ b/packages/imperative/src/imperative/src/config/cmd/convert-profiles/convert-profiles.handler.ts @@ -67,7 +67,7 @@ export default class ConvertProfilesHandler implements ICommandHandler { } if (oldPluginInfo.plugins.length == 0 && oldProfileCount === 0) { - params.response.console.log("No old profiles were found to convert from Zowe v1 to v2."); + params.response.console.log("No old profiles were found to convert from Zowe v1 to TeamConfig."); // Exit if we're not deleting if (!(params.arguments.delete != null && params.arguments.delete === true)) { return; @@ -79,7 +79,7 @@ export default class ConvertProfilesHandler implements ICommandHandler { // If this is true, then we know that we want to delete, but there is nothing to convert first. if (!skipConversion) { if (oldProfileCount > 0) { - params.response.console.log(`Detected ${oldProfileCount} old profile(s) to convert from Zowe v1 to v2.\n`); + params.response.console.log(`Detected ${oldProfileCount} old profile(s) to convert from Zowe v1 to TeamConfig.\n`); } if (oldPluginInfo.plugins.length > 0) { diff --git a/packages/imperative/src/imperative/src/config/cmd/report-env/EnvItems.ts b/packages/imperative/src/imperative/src/config/cmd/report-env/EnvItems.ts index bd5a9f8344..bf72572e61 100644 --- a/packages/imperative/src/imperative/src/config/cmd/report-env/EnvItems.ts +++ b/packages/imperative/src/imperative/src/config/cmd/report-env/EnvItems.ts @@ -18,7 +18,6 @@ export enum ItemId { ZOWE_VER, NODEJS_VER, - NVM_VER, PLATFORM, ARCHITECTURE, OS_PATH, @@ -27,7 +26,7 @@ export enum ItemId { ZOWE_IMPERATIVE_LOG_LEVEL, OTHER_ZOWE_VARS, // Zowe variables not listed above NPM_VER, - ZOWE_CONFIG_TYPE, // detect if we have V1 profiles or V2 config + ZOWE_CONFIG_INFO, ZOWE_PLUGINS } diff --git a/packages/imperative/src/imperative/src/config/cmd/report-env/EnvQuery.ts b/packages/imperative/src/imperative/src/config/cmd/report-env/EnvQuery.ts index 577b7100a0..385493e968 100644 --- a/packages/imperative/src/imperative/src/config/cmd/report-env/EnvQuery.ts +++ b/packages/imperative/src/imperative/src/config/cmd/report-env/EnvQuery.ts @@ -9,7 +9,6 @@ * */ -import * as fs from "fs"; import * as os from "os"; import * as lodash from "lodash"; import * as path from "path"; @@ -18,7 +17,6 @@ import { StdioOptions } from "child_process"; import { ConfigConstants, IConfigProfile } from "../../../../../config"; import { IHandlerProgressApi } from "../../../../../cmd"; -import { IO } from "../../../../../io"; import { ImperativeConfig , TextUtils } from "../../../../../utilities"; import { ITaskWithStatus, TaskProgress, TaskStage } from "../../../../../operations"; import { CliUtils } from "../../../../../utilities/src/CliUtils"; @@ -83,11 +81,6 @@ export class EnvQuery { getResult.itemValMsg = "Node.js version = " + getResult.itemVal; break; } - case ItemId.NVM_VER: { - getResult.itemVal = EnvQuery.getCmdOutput("nvm", ["version"]); - getResult.itemValMsg = "Node Version Manager version = " + getResult.itemVal; - break; - } case ItemId.PLATFORM: { getResult.itemVal = os.platform(); getResult.itemValMsg = "O.S. platform = " + getResult.itemVal; @@ -130,7 +123,7 @@ export class EnvQuery { await EnvQuery.getNpmInfo(getResult, getItemOpts); break; } - case ItemId.ZOWE_CONFIG_TYPE: { + case ItemId.ZOWE_CONFIG_INFO: { await EnvQuery.getConfigInfo(getResult, getItemOpts); break; } @@ -218,8 +211,7 @@ export class EnvQuery { private static async getConfigInfo( getResult: IGetItemVal, getItemOpts: IGetItemOpts ): Promise { - const teamCfg: string = "V2 Team Config"; - const v1Profiles = "V1 Profiles"; + const teamCfg: string = "Team Config"; const doesProgBarExist: boolean = (getItemOpts?.progressApi) ? true: false; // setup progress bar @@ -231,12 +223,8 @@ export class EnvQuery { if (ImperativeConfig.instance.config?.exists) { getResult.itemVal = teamCfg; - configProgress.statusMessage = "Retrieving V2 configuration"; + configProgress.statusMessage = "Retrieving Zowe client configuration"; configProgress.percentComplete = TaskProgress.TWENTY_PERCENT; - } else { - getResult.itemVal = v1Profiles; - configProgress.statusMessage = "Retrieving V1 configuration"; - configProgress.percentComplete = TaskProgress.FIFTY_PERCENT; } if (doesProgBarExist) { @@ -262,11 +250,10 @@ export class EnvQuery { } else { getResult.itemValMsg += "off"; } - getResult.itemValMsg += `${os.EOL}Zowe config type = ` + getResult.itemVal; if ( getResult.itemVal == teamCfg) { // Display all relevant zowe team config files. - configProgress.statusMessage = "Retrieving active team config files"; + configProgress.statusMessage = "Retrieving active Zowe client config files"; configProgress.percentComplete = TaskProgress.THIRTY_PERCENT; await EnvQuery.updateProgressBar(doesProgBarExist); const config = ImperativeConfig.instance.config; @@ -288,7 +275,7 @@ export class EnvQuery { } } - getResult.itemValMsg += `${os.EOL}Team config files in effect:${os.EOL}`; + getResult.itemValMsg += `${os.EOL}Zowe client config files in use:${os.EOL}`; for (const configLoc of Object.keys(configListObj)) { getResult.itemValMsg += EnvQuery.indent + configLoc + os.EOL; } @@ -341,40 +328,7 @@ export class EnvQuery { getResult.itemValMsg += EnvQuery.indent + profPathNm + os.EOL; } } else { - // display V1 profile information - configProgress.statusMessage = "Retrieving available profile names"; - configProgress.percentComplete = TaskProgress.NINETY_PERCENT; - await EnvQuery.updateProgressBar(doesProgBarExist); - - getResult.itemValMsg += `${os.EOL}Available profiles:${os.EOL}`; - const v1ProfilesDir = path.normalize(ImperativeConfig.instance.cliHome + "/profiles"); - if (IO.isDir(v1ProfilesDir)) { - // read all of the subdirectories of the profiles directory - fs.readdirSync(v1ProfilesDir).forEach((nextProfileTypeNm) => { - const profileTypeDir = path.normalize(v1ProfilesDir + "/" + nextProfileTypeNm); - let profilesOfCurrType: string = ""; - - // is the next candidate for nextProfileTypeNm a directory? - if (IO.isDir(profileTypeDir)) { - // does the next profile type directory have any profiles? - fs.readdirSync(profileTypeDir).forEach((nextProfileNm) => { - // exclude the meta files - if (nextProfileNm.endsWith("_meta.yaml")) { - return; - } - profilesOfCurrType += EnvQuery.indent + EnvQuery.indent + - nextProfileNm.replace(".yaml", "") + os.EOL; - }); - } - - // did we find any profiles? - if (profilesOfCurrType.length > 0) { - getResult.itemValMsg += EnvQuery.indent + nextProfileTypeNm + - " profiles: " + os.EOL + profilesOfCurrType; - - } - }); - } + getResult.itemValMsg += `${os.EOL}No Zowe client configuration detected.${os.EOL}`; } // add indent to each line diff --git a/packages/imperative/src/imperative/src/config/cmd/report-env/Report-env.handler.ts b/packages/imperative/src/imperative/src/config/cmd/report-env/Report-env.handler.ts index 9b3005f989..21139e523f 100644 --- a/packages/imperative/src/imperative/src/config/cmd/report-env/Report-env.handler.ts +++ b/packages/imperative/src/imperative/src/config/cmd/report-env/Report-env.handler.ts @@ -45,7 +45,7 @@ export default class ReportEnvHandler implements ICommandHandler { )) { // These items have a progress bar. Output a newline beforehand. - if (nextItemId == ItemId.NPM_VER || nextItemId == ItemId.ZOWE_CONFIG_TYPE) { + if (nextItemId == ItemId.NPM_VER || nextItemId == ItemId.ZOWE_CONFIG_INFO) { responseApi.console.error(EOL); } await this.displayEnvItem(nextItemId, responseApi); diff --git a/packages/imperative/src/imperative/src/profiles/ImperativeProfileManagerFactory.ts b/packages/imperative/src/imperative/src/profiles/ImperativeProfileManagerFactory.ts deleted file mode 100644 index 8da02adabd..0000000000 --- a/packages/imperative/src/imperative/src/profiles/ImperativeProfileManagerFactory.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { AbstractProfileManagerFactory } from "../../../profiles"; -import { CliProfileManager, ICommandProfileTypeConfiguration } from "../../../cmd/"; -import { ImperativeApi } from "../api/ImperativeApi"; -/** - * The imperative profile manager factory returns instances of the cli profile manager - * @export - * @class ProfileManagerFactory - * @extends {AbstractProfileManagerFactory} - */ -export class ImperativeProfileManagerFactory extends AbstractProfileManagerFactory { - private mImperativeApi: ImperativeApi; - constructor(imperativeApi: ImperativeApi) { - super(); - this.mImperativeApi = imperativeApi; - } - /** - * Returns a instance of the CliProfileManager - * @param {string} type - The profile type you want to manage. - * @returns {CliProfileManager} - The profile manager instance - * @memberof ProfileManagerFactory - */ - public getManager(type: string): CliProfileManager { - return this.mImperativeApi.profileManager(type); - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/CompleteProfilesGroupBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/CompleteProfilesGroupBuilder.ts deleted file mode 100644 index c84f5d08d9..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/CompleteProfilesGroupBuilder.ts +++ /dev/null @@ -1,143 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ICommandDefinition } from "../../../../cmd"; -import { - createProfilesCommandDesc, createProfilesCommandSummary, - deleteProfilesCommandDesc, deleteProfilesCommandSummary, - listProfileCommandDesc, listProfileCommandSummary, - setProfileActionDesc, setProfileActionSummary, - updateProfileCommandDesc, updateProfileCommandSummary, - validateProfileGroupDesc, validateProfileCommandSummary -} from "../../../../messages"; -import { Constants } from "../../../../constants"; -import { ProfilesCreateCommandBuilder } from "./ProfilesCreateCommandBuilder"; -import { ProfilesUpdateCommandBuilder } from "./ProfilesUpdateCommandBuilder"; -import { ProfilesDeleteCommandBuilder } from "./ProfilesDeleteCommandBuilder"; -import { ProfilesValidateCommandBuilder } from "./ProfilesValidateCommandBuilder"; -import { ProfilesListCommandBuilder } from "./ProfilesListCommandBuilder"; -import { ProfilesSetCommandBuilder } from "./ProfilesSetCommandBuilder"; -import { Logger } from "../../../../logger/index"; -import { IProfileTypeConfiguration, ProfilesConstants } from "../../../../profiles"; -import { ImperativeConfig } from "../../../../utilities"; - -/** - * Generate a complete group of commands for maintaining configuration profiles - * based on provided profile definitions. - */ -export class CompleteProfilesGroupBuilder { - - - /** - * Get the complete profile group of commands - * @param {ICommandProfileTypeConfiguration[]} profiles - the profile configurations to convert to commands - * @param {Logger} logger - logger to use in the builder classes - * @returns {ICommandDefinition} - the complete profile group of commands - */ - public static getProfileGroup(profiles: IProfileTypeConfiguration[], logger: Logger): ICommandDefinition { - - const profileGroup: ICommandDefinition = { - name: Constants.PROFILE_GROUP, - summary: "Create and manage configuration profiles", - description: "Create and manage configuration profiles.", - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_INIT, - children: [] - }; - - const createGroup: ICommandDefinition = { - name: Constants.CREATE_ACTION, - description: createProfilesCommandDesc.message, - summary: createProfilesCommandSummary.message, - aliases: ["cre"], - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_INIT, - children: [], - }; - - const deleteGroup: ICommandDefinition = { - name: Constants.DELETE_ACTION, - description: deleteProfilesCommandDesc.message, - summary: deleteProfilesCommandSummary.message, - aliases: ["rm"], - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_EDIT + " " + - ImperativeConfig.instance.config.formMainConfigPathNm({addPath: false}), - children: [], - }; - - const setGroup: ICommandDefinition = { - name: Constants.SET_ACTION, - summary: setProfileActionSummary.message, - description: setProfileActionDesc.message, - type: "group", - aliases: ["set"], - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_SET, - children: [], - }; - - const updateGroup: ICommandDefinition = { - name: Constants.UPDATE_ACTION, - description: updateProfileCommandDesc.message, - summary: updateProfileCommandSummary.message, - aliases: ["upd"], - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_SET, - children: [], - }; - - const validateGroup: ICommandDefinition = { - name: Constants.VALIDATE_ACTION, - description: validateProfileGroupDesc.message, - summary: validateProfileCommandSummary.message, - aliases: ["val"], - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_EDIT + " " + - ImperativeConfig.instance.config.formMainConfigPathNm({addPath: false}), - children: [], - }; - - const listGroup: ICommandDefinition = { - name: Constants.LIST_ACTION, - description: listProfileCommandDesc.message, - summary: listProfileCommandSummary.message, - aliases: ["ls"], - type: "group", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_LIST, - children: [], - }; - - for (const profile of profiles) { - const createCommandAction = new ProfilesCreateCommandBuilder(profile.type, logger, profile); - const updateCommandAction = new ProfilesUpdateCommandBuilder(profile.type, logger, profile); - const deleteCommandAction = new ProfilesDeleteCommandBuilder(profile.type, logger, profile); - const validateCommandAction = new ProfilesValidateCommandBuilder(profile.type, logger, profile); - const listCommandAction = new ProfilesListCommandBuilder(profile.type, logger, profile); - const setCommandAction = new ProfilesSetCommandBuilder(profile.type, logger, profile); - updateGroup.children.push(updateCommandAction.build()); - deleteGroup.children.push(deleteCommandAction.build()); - // validate profile is optional depending on if the profile has a validation plan - const validateCommandResult = validateCommandAction.build(); - if (validateCommandResult != null) { - validateGroup.children.push(validateCommandResult); - } - listGroup.children.push(listCommandAction.build()); - createGroup.children.push(createCommandAction.build()); - setGroup.children.push(setCommandAction.build()); - } - profileGroup.children.push(createGroup, updateGroup, deleteGroup, listGroup, setGroup); - if (validateGroup.children.length > 0) { - // don't bother to add validation commands unless some plans have been provided - profileGroup.children.push(validateGroup); - } - return profileGroup; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesCommandBuilder.ts deleted file mode 100644 index 997a11ad80..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesCommandBuilder.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { AbstractCommandBuilder } from "../../../../cmd/src/builders/AbstractCommandBuilder"; -import { isNullOrUndefined } from "util"; -import { ICommandDefinition, ICommandOptionDefinition, ICommandProfileTypeConfiguration } from "../../../../cmd"; -import { Logger } from "../../../../logger"; -import { IProfileSchema, ProfileUtils } from "../../../../profiles"; -import { ICommandProfileProperty } from "../../../../cmd/src/doc/profiles/definition/ICommandProfileProperty"; - -/** - * Abstract class for generating profile-related commands - */ -export abstract class ProfilesCommandBuilder implements AbstractCommandBuilder { - - /** - * Schema for the command. - */ - protected mSchema: IProfileSchema; - - /** - * Construct the builder based on the schema. - * @param mProfileType - the name of the profile type e.g. banana - * @param {Logger} mLogger - logger instance to use for the builder class - * @param {IProfileSchema} mProfileConfig: The schema that describes the profile - */ - constructor(protected mProfileType: string, - protected mLogger: Logger, - protected mProfileConfig: ICommandProfileTypeConfiguration) { - - this.mSchema = mProfileConfig.schema; - if (isNullOrUndefined(this.mSchema)) { - throw new Error(`Profile Builder Error: No profile schema was supplied.`); - } - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public abstract buildFull(): ICommandDefinition; - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public abstract getAction(): string; - - /** - * Only constructs the "group" command segment for the document. Use this if the command definition - * document already includes a "create" verb. - * @return {ICommandDefinition} - */ - public build(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected abstract buildProfileSegmentFromSchema(): ICommandDefinition ; - - /** - * Construct the operands from the Zowe Profile Schema. - * @param {any} properties: The properties set to iterate over looking for operands to add - * @param {ICommandOptionDefinition[]} options: The final option definitions to add. - * @return {ICommandOptionDefinition[]}: The set of returned option definitions - */ - protected buildOptionsFromProfileSchema(properties: any, - options: ICommandOptionDefinition[]): ICommandOptionDefinition[] { - for (const propName of Object.keys(properties)) { - // helper to recursively add any nested option definitions - const findAndAddOptions = (propertiesObject: any, propertyName: string) => { - const field: ICommandProfileProperty = propertiesObject[propertyName]; - if (!isNullOrUndefined(field.optionDefinition)) { - options.push(field.optionDefinition); - } - if (!isNullOrUndefined(field.optionDefinitions)) { - options = options.concat(field.optionDefinitions); - } - if (field.properties != null) { - for (const nestedProperty of Object.keys(field.properties)) { - findAndAddOptions(field.properties, nestedProperty); - } - } - }; - findAndAddOptions(properties, propName); - } - if (!isNullOrUndefined(this.mProfileConfig.dependencies)) { - for (const dependency of this.mProfileConfig.dependencies) { - const description = dependency.description || - "The name of a " + dependency.type + " profile to associate with this profile."; - const dependencyOption: ICommandOptionDefinition = { - name: ProfileUtils.getProfileOption(dependency.type), - aliases: [ProfileUtils.getProfileOptionAlias(dependency.type)], - type: "string", - description, - required: dependency.required - }; - options.push(dependencyOption); - } - } - return options; - } - -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesCreateCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesCreateCommandBuilder.ts deleted file mode 100644 index e79f4df129..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesCreateCommandBuilder.ts +++ /dev/null @@ -1,99 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { ICommandDefinition, ICommandProfileTypeConfiguration } from "../../../../cmd"; -import { createProfileCommandSummary, createProfileOptionDesc, createProfileOptionOverwriteDesc, - createProfileDisableDefaultsDesc } from "../../../../messages"; -import { Constants } from "../../../../constants"; -import { TextUtils } from "../../../../utilities"; -import { Logger } from "../../../../logger/index"; -import { ProfilesConstants, ProfileUtils } from "../../../../profiles"; - -/** - * Used to build profile create command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesCreateCommandBuilder extends ProfilesCommandBuilder { - - /** - * Construct the builder based on the schema. - * @param {string} profileType - the type name for the profile - * @param {Logger} logger - logger instance to use for the builder class - * @param {ICommandProfileTypeConfiguration} profileConfig: Imperative profile configuration for this type of profile - */ - constructor(profileType: string, logger: Logger, profileConfig: ICommandProfileTypeConfiguration) { - super(profileType, logger, profileConfig); - } - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.CREATE_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(createProfileCommandSummary.message, - {type: this.mProfileType}), - description: this.mSchema.description, - type: "command", - handler: __dirname + "/../handlers/CreateProfilesHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_INIT, - customize: {}, - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(createProfileOptionDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "string", - required: true, - }], - options: this.buildOptionsFromProfileSchema(this.mSchema.properties, []) - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - profileCommand.options.push({ - name: Constants.OVERWRITE_OPTION, aliases: ["ow"], - description: TextUtils.formatMessage(createProfileOptionOverwriteDesc.message, - {type: this.mProfileType}), - type: "boolean" - }); - profileCommand.options.push({ - name: Constants.DISABLE_DEFAULTS_OPTION, aliases: ["dd"], - description: TextUtils.formatMessage(createProfileDisableDefaultsDesc.message, - {type: this.mProfileType}), - type: "boolean" - }); - - if (this.mProfileConfig.createProfileExamples != null) { - profileCommand.examples = this.mProfileConfig.createProfileExamples; - } - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesDeleteCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesDeleteCommandBuilder.ts deleted file mode 100644 index c5174b1f22..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesDeleteCommandBuilder.ts +++ /dev/null @@ -1,102 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { Constants } from "../../../../constants"; -import { ICommandDefinition } from "../../../../cmd"; -import { - deleteProfileActionDesc, - deleteProfileCommandDesc, - deleteProfileExample, - deleteProfileForceOptionDesc, - deleteProfileNameDesc -} from "../../../../messages/index"; -import { ImperativeConfig, TextUtils } from "../../../../utilities"; -import { ProfilesConstants, ProfileUtils } from "../../../../profiles"; - -/** - * Used to build delete profile command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesDeleteCommandBuilder extends ProfilesCommandBuilder { - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.DELETE_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(deleteProfileActionDesc.message, - {type: this.mProfileType}), - description: TextUtils.formatMessage(deleteProfileCommandDesc.message, - {type: this.mProfileType}), - type: "command", - handler: __dirname + "/../handlers/NewDeleteProfilesHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_EDIT + - "\n " + ImperativeConfig.instance.config.formMainConfigPathNm({addPath: false}), - customize: {}, - options: [], - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(deleteProfileNameDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "string", - required: true, - }], - examples: [ - { - options: "profilename", - description: TextUtils.formatMessage(deleteProfileExample.message, - { - type: this.mProfileType, - name: "profilename" - }) - } - ] - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - - profileCommand.options.push({ - name: "force", - aliases: [], - description: TextUtils.formatMessage(deleteProfileForceOptionDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "boolean", - required: false, - }); - - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesListCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesListCommandBuilder.ts deleted file mode 100644 index 084b9b37d3..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesListCommandBuilder.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { Constants } from "../../../../constants"; -import { ICommandDefinition, ICommandProfileTypeConfiguration } from "../../../../cmd"; -import { - listProfileCommandDesc, - listProfileExample, - listProfileExampleShowContents, - listProfileVerboseOptionDesc -} from "../../../../messages"; -import { TextUtils } from "../../../../utilities"; -import { Logger } from "../../../../logger/"; -import { ProfilesConstants } from "../../../../profiles"; - -/** - * Used to build profile update command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesListCommandBuilder extends ProfilesCommandBuilder { - /** - * Construct the builder based on the schema. - * @param profileType - the profile type to generate the command definition for - * @param {Logger} logger - logger instance to use for the builder class - * @param {ICommandProfileTypeConfiguration} profileConfig: Imperative profile configuration for this type of profile - */ - constructor(profileType: string, logger: Logger, profileConfig: ICommandProfileTypeConfiguration) { - super(profileType, logger, profileConfig); - } - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.LIST_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profiles", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(listProfileCommandDesc.message, - {type: this.mProfileType}), - description: this.mSchema.description, - type: "command", - handler: __dirname + "/../handlers/ListProfilesHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_LIST, - customize: {}, - options: [ - { - name: "show-contents", - aliases: ["sc"], - description: TextUtils.formatMessage(listProfileVerboseOptionDesc.message, - { - type: this.mProfileType - }), - type: "boolean", - required: false - } - - ], - examples: [ - { - options: "", - description: TextUtils.formatMessage(listProfileExample.message, - { - type: this.mProfileType - }), - }, - { - options: "--sc", - description: TextUtils.formatMessage(listProfileExampleShowContents.message, - { - type: this.mProfileType - }), - } - ] - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesSetCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesSetCommandBuilder.ts deleted file mode 100644 index b628451d16..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesSetCommandBuilder.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { ICommandDefinition } from "../../../../cmd"; -import { TextUtils } from "../../../../utilities"; -import { Constants } from "../../../../constants"; -import { - setGroupWithOnlyProfilesCommandDesc, - setGroupWithOnlyProfilesSummary, - setProfileExample, - setProfileOptionDesc -} from "../../../../messages/index"; -import { ProfilesConstants } from "../../../../profiles"; - -/** - * Used to build "set default profile" command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesSetCommandBuilder extends ProfilesCommandBuilder { - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.SET_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(setGroupWithOnlyProfilesSummary.message, - {type: this.mProfileType}), - description: TextUtils.formatMessage(setGroupWithOnlyProfilesCommandDesc.message, - {type: this.mProfileType}), - type: "command", - handler: __dirname + "/../handlers/SetDefaultProfilesHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_SET, - options: [], - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(setProfileOptionDesc.message, - { - type: this.mProfileType, - }), - type: "string", - required: true, - }], - customize: {}, - examples: [{ - options: "profilename", - description: TextUtils.formatMessage(setProfileExample.message, { - type: this.mProfileType, - name: "profilename" - }), - } - ] - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesShowDependenciesCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesShowDependenciesCommandBuilder.ts deleted file mode 100644 index 408d3b9de5..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesShowDependenciesCommandBuilder.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { Constants } from "../../../../constants"; -import { ICommandDefinition } from "../../../../cmd"; -import { deleteProfileNameDesc, showDependenciesCommandDesc } from "../../../../messages"; -import { TextUtils } from "../../../../utilities"; -import { ProfilesConstants, ProfileUtils } from "../../../../profiles"; - -/** - * Used to build profile create command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesShowDependenciesCommandBuilder extends ProfilesCommandBuilder { - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.SHOW_DEPS_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(showDependenciesCommandDesc.message, - {type: this.mProfileType}), - description: this.mSchema.description, - type: "command", - handler: __dirname + "/../handlers/ShowDependenciesProfilesHandler", - customize: {}, - options: [], - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(deleteProfileNameDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "string", - required: true, - }] - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesUpdateCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesUpdateCommandBuilder.ts deleted file mode 100644 index fb4bccd8c7..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesUpdateCommandBuilder.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { isNullOrUndefined } from "util"; -import { Constants } from "../../../../constants"; -import { ICommandDefinition } from "../../../../cmd"; -import { createProfileOptionDesc, updateProfileCommandDesc } from "../../../../messages"; -import { TextUtils } from "../../../../utilities"; -import { IProfileProperty, ProfilesConstants, ProfileUtils } from "../../../../profiles"; -import { ICommandProfileProperty } from "../../../../cmd/src/doc/profiles/definition/ICommandProfileProperty"; - -/** - * Used to build profile update command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesUpdateCommandBuilder extends ProfilesCommandBuilder { - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.UPDATE_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - - // clone the properties file before trying to modify them so that we don't affect the original - const updateOnlyProperties: { [key: string]: IProfileProperty } = - JSON.parse(JSON.stringify(this.mSchema.properties)); - for (const propName of Object.keys(updateOnlyProperties)) { - // helper to tweak all nested option definitions - // for updating the profile (marking required options - // optional in case the user does not wish to update them) - const processFieldsForUpdate = (properties: any, propertyName: string) => { - const field: ICommandProfileProperty = properties[propertyName]; - if (!isNullOrUndefined(field.optionDefinition)) { - field.optionDefinition.required = false; - field.optionDefinition.absenceImplications = null; - field.optionDefinition.implies = null; - } - if (!isNullOrUndefined(field.optionDefinitions)) { - for (const anOption of field.optionDefinitions) { - if (!isNullOrUndefined(anOption.required)) { - anOption.required = false; - anOption.absenceImplications = null; - anOption.implies = null; - } - } - } - if (field.properties != null) { - for (const nestedProperty of Object.keys(field.properties)) { - processFieldsForUpdate(field.properties, nestedProperty); - } - } - }; - processFieldsForUpdate(updateOnlyProperties, propName); - } - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(updateProfileCommandDesc.message, - {type: this.mProfileType}), - description: this.mSchema.description, - type: "command", - handler: __dirname + "/../handlers/UpdateProfilesHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_SET, - customize: {}, - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(createProfileOptionDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "string", - required: true, - }], - options: this.buildOptionsFromProfileSchema(updateOnlyProperties, []), - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - - if (this.mProfileConfig.updateProfileExamples != null) { - profileCommand.examples = this.mProfileConfig.updateProfileExamples; - } - - // We don't want to override existing settings with defaultValue for an option - for (const option of profileCommand.options) { - delete option.defaultValue; - } - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/builders/ProfilesValidateCommandBuilder.ts b/packages/imperative/src/imperative/src/profiles/builders/ProfilesValidateCommandBuilder.ts deleted file mode 100644 index c8f6113f78..0000000000 --- a/packages/imperative/src/imperative/src/profiles/builders/ProfilesValidateCommandBuilder.ts +++ /dev/null @@ -1,90 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ProfilesCommandBuilder } from "./ProfilesCommandBuilder"; -import { ICommandDefinition, ICommandProfileTypeConfiguration } from "../../../../cmd"; -import { Constants } from "../../../../constants"; -import { deleteProfileNameDesc, validateProfileCommandDesc } from "../../../../messages"; -import { ImperativeConfig, TextUtils } from "../../../../utilities"; -import { Logger } from "../../../../logger/index"; -import { isNullOrUndefined } from "util"; -import { ProfilesConstants, ProfileUtils, ProfileValidator } from "../../../../profiles"; - -/** - * Used to build profile validate command definitions. - * Used automatically if you allow the "profiles" command group to be generated - */ -export class ProfilesValidateCommandBuilder extends ProfilesCommandBuilder { - - /** - * Construct the builder based on the schema. - * @param profileType - the name of the profile type to build the command for - * @param {Logger} logger - logger to use while building command definition - * @param {ICommandProfileTypeConfiguration} profileConfig: Imperative profile configuration for this type of profile - */ - constructor(profileType: string, logger: Logger, profileConfig: ICommandProfileTypeConfiguration) { - super(profileType, logger, profileConfig); - } - - /** - * Gets the "action" that this command builder is building. - * @return {string}: The "create" action string - */ - public getAction(): string { - return Constants.VALIDATE_ACTION; - } - - /** - * Build the full command - includes action group and object command. - * @return {ICommandDefinition}: The command definition. - */ - public buildFull(): ICommandDefinition { - return this.buildProfileSegmentFromSchema(); - } - - /** - * Builds only the "profile" segment from the profile schema. - * @return {ICommandDefinition} - */ - protected buildProfileSegmentFromSchema(): ICommandDefinition { - if (isNullOrUndefined(this.mProfileConfig.validationPlanModule)) { - return undefined; - } - const profileCommand: ICommandDefinition = { - name: this.mProfileType + "-profile", - aliases: [this.mProfileType], - summary: TextUtils.formatMessage(validateProfileCommandDesc.message, - {type: this.mProfileType}), - description: TextUtils.formatMessage(validateProfileCommandDesc.message, - {type: this.mProfileType}), - type: "command", - handler: __dirname + "/../handlers/ValidateProfileHandler", - deprecatedReplacement: ProfilesConstants.DEPRECATE_TO_CONFIG_EDIT + - "\n " + ImperativeConfig.instance.config.formMainConfigPathNm({addPath: false}), - customize: {}, - options: [ProfileValidator.PRINT_PLAN_OPTION], - positionals: [{ - name: Constants.PROFILE_NAME_OPTION, - description: TextUtils.formatMessage(deleteProfileNameDesc.message, - { - type: this.mProfileType, - typeOption: ProfileUtils.getProfileOption(this.mProfileType) - }), - type: "string", - required: false - }] - }; - profileCommand.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY] = this.mProfileType; - - - return profileCommand; - } -} diff --git a/packages/imperative/src/imperative/src/profiles/handlers/CreateProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/CreateProfilesHandler.ts deleted file mode 100644 index dc588f06a8..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/CreateProfilesHandler.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { overroteProfileMessage, profileCreatedSuccessfullyAndPath, profileReviewMessage } from "../../../../messages"; -import { Imperative } from "../../Imperative"; -import { IProfileSaved, ISaveProfileFromCliArgs, ProfilesConstants } from "../../../../profiles"; -import { CliProfileManager, ICommandHandler, IHandlerParameters } from "../../../../cmd"; - -import { Constants } from "../../../../constants"; -import { TextUtils } from "../../../../utilities"; - -/** - * Handler that allows creation of a profile from command line arguments. Intended for usage with the automatically - * generated profile create commands, but can be used otherwise. - * @export - * @class CreateProfilesHandler - * @implements {ICommandHandler} - */ -export default class CreateProfilesHandler implements ICommandHandler { - /** - * Create a profile from command line arguments. - * @param {IHandlerParameters} commandParameters - Standard Imperative command handler parameters - see the - * interface for full details - * @memberof CreateProfilesHandler - */ - public async process(commandParameters: IHandlerParameters) { - const profileType: string = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - let profileManager: CliProfileManager; - - try { - profileManager = Imperative.api.profileManager(profileType); - } catch (error) { - // profileIO error is thrown when calling old profile functions in team config mode. - commandParameters.response.console.error( - "An error occurred trying to create a profile.\n" + error.message - ); - return; - } - - const profileName = commandParameters.arguments[Constants.PROFILE_NAME_OPTION]; - const createParms: ISaveProfileFromCliArgs = { - name: profileName, - type: profileType, - args: commandParameters.arguments, - overwrite: commandParameters.arguments.overwrite, - disableDefaults: commandParameters.arguments.disableDefaults, - profile: {} - }; - /** - * Create the profile based on the command line arguments passed - */ - const createResponse: IProfileSaved = await profileManager.save(createParms); - - /** - * Indicate to the user (if specified) that the profile was overwritten - */ - if (createResponse.overwritten) { - commandParameters.response.console.log(overroteProfileMessage.message, { - profileOption: commandParameters - .arguments[Constants.PROFILE_NAME_OPTION] - }); - } - - /** - * Formulate th remainder of the response - which - */ - commandParameters.response.console.log(profileCreatedSuccessfullyAndPath.message); - commandParameters.response.console.log(createResponse.path); - commandParameters.response.console.log(""); - commandParameters.response.console.log(TextUtils.prettyJson(createResponse.profile, - undefined, undefined, "\n")); - commandParameters.response.console.log(profileReviewMessage.message); - } -} - diff --git a/packages/imperative/src/imperative/src/profiles/handlers/ListProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/ListProfilesHandler.ts deleted file mode 100644 index 2d33126600..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/ListProfilesHandler.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { Imperative } from "../../../"; -import { ProfilesConstants } from "../../../../profiles/src/constants/ProfilesConstants"; -import { CliProfileManager, ICommandHandler, IHandlerParameters } from "../../../../cmd"; -import { IProfileLoaded } from "../../../.."; - -/** - * Handler for the auto-generated list profiles command. - */ -export default class ListProfilesHandler implements ICommandHandler { - - /** - * The process command handler for the "list profiles" command. - * @return {Promise}: The promise to fulfill when complete. - */ - public async process(params: IHandlerParameters): Promise { - let profileManager: CliProfileManager; - - // Extract the profile type - const profileType: string = params.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - - try { - // Extract the profile manager - profileManager = Imperative.api.profileManager(profileType); - } catch (error) { - // profileIO error is thrown when calling old profile functions in team config mode. - params.response.console.error( - "An error occurred trying to list profiles.\n" + error.message - ); - return; - } - - // Extract the default profile - const defaultName: string = profileManager.getDefaultProfileName(); - - // Load all profiles for the type contained in the manager - const loadResults: IProfileLoaded[] = await profileManager.loadAll( - {noSecure: true, typeOnly: true} - ); - - // Set the data object - params.response.data.setMessage(`"${loadResults.length}" profiles loaded for type "${profileType}"`); - params.response.data.setObj(loadResults); - - // Construct the format print list - const print = []; - for (const result of loadResults) { - if (result.name === defaultName) { - result.name += " (default) "; - } - - print.push({ - name: result.name, - contents: result.profile - }); - - } - - // Format the results accord to the contents - if (params.arguments.showContents) { - params.response.format.output({ - output: print, - format: "object" - }); - } else { - params.response.format.output({ - output: print, - fields: ["name"], - format: "list" - }); - } - } -} - diff --git a/packages/imperative/src/imperative/src/profiles/handlers/NewDeleteProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/NewDeleteProfilesHandler.ts deleted file mode 100644 index ac12434759..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/NewDeleteProfilesHandler.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IHandlerParameters } from "../../../../cmd"; -import { Imperative } from "../../Imperative"; -import { Constants } from "../../../../constants"; -import { IProfileDeleted, ProfilesConstants } from "../../../../profiles"; - -export default class NewDeleteProfilesHandler { - public async process(commandParameters: IHandlerParameters) { - const profileType = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - const profileName: string = commandParameters.arguments[Constants.PROFILE_NAME_OPTION]; - let deleted: IProfileDeleted; - - try { - deleted = await Imperative.api.profileManager(profileType).delete({ - name: profileName, - rejectIfDependency: !commandParameters.arguments.force || false - }); - } catch (error) { - // profileIO error is thrown when calling old profile functions in team config mode. - commandParameters.response.console.error( - "An error occurred trying to delete a profile.\n" + error.message - ); - return; - } - - if (!deleted.defaultCleared) { - commandParameters.response.console.log(`Your profile named ${profileName} of type ${profileType} was successfully deleted.`); - } else { - commandParameters.response.console.log(`Your default profile named ${profileName} of type ${profileType} was successfully deleted.\n` + - `Because you deleted it, the default profile for type ${profileType} has been cleared.\nTo set a new default profile, run "zowe ` + - `profiles set-default ${profileType} ".`); - } - } -} diff --git a/packages/imperative/src/imperative/src/profiles/handlers/OldDeleteProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/OldDeleteProfilesHandler.ts deleted file mode 100644 index e7891d4028..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/OldDeleteProfilesHandler.ts +++ /dev/null @@ -1,260 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -// // import { isNullOrUndefined } from "util"; -// import { CommandResponse, ICommandHandler, IHandlerParameters } from "../../../../cmd"; -// import { Constants } from "../../../../constants"; -// import { ProfileManager } from "../../ProfileManager"; -// import { -// profileDeletedSuccessfully, -// profileDeleteErrorDetails, -// profileDeleteErrorHeader, -// profileNotDeletedMessage, -// unableToDeleteProfile, -// unableToFindProfile -// } from "../../../../messages"; -// import { TextUtils } from "../../../../utilities"; -// import { IProfileDeleted } from "../../doc/response/IProfileDeleted"; -// import { IProfile } from "../../../index"; -// import { IProfileLoaded } from "../../doc/response/IProfileLoaded"; -// import { Imperative } from "../../../../index"; -// import { ProfileUtils } from "../../ProfileUtils"; -// import { ProfilesConstants } from "../../constants/ProfilesConstants"; - -// /** -// * Handler for the auto-generated delete profiles command. -// * Deletes requested user configuration profiles -// */ -// export default class DeleteProfilesHandler implements ICommandHandler { -// private rejectCommand: any; -// private response: CommandResponse; - -// /** -// * The process command handler for the "delete profile" command. -// * @return {Promise}: The promise to fulfill when complete. -// */ -// public process(commandParameters: IHandlerParameters): Promise { - -// /** -// * Invoke the modules profile creator. -// */ -// const errors: string[] = []; -// const shouldForce: boolean = commandParameters.arguments.force; -// const profileList: Map = new Map(); -// const profileType = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; -// const profileSpecified: string = commandParameters.arguments[Constants.PROFILE_NAME_OPTION]; - -// let loadedProfile: IProfile; -// return new Promise((commandComplete, rejectCommand) => { -// this.rejectCommand = rejectCommand; -// new ProfileManager(profileType) -// .loadProfile({ name: profileSpecified }).then((profileResponse) => { -// loadedProfile = profileResponse.profile; -// profileList.set(profileType, [loadedProfile]); -// const loadPromises: Array> = []; -// if (!isNullOrUndefined(loadedProfile.dependencies) && -// commandParameters.arguments[Constants.PROFILE_DELETE_PROFILE_DEPS]) { -// for (const entry of loadedProfile.dependencies) { -// const loadPromise: Promise = -// new ProfileManager({ -// type: profileType, -// allTypeConfigs: Imperative.loadedConfig.profiles, -// profileDir: ProfileUtils.constructProfilesDir() -// }).loadProfile({ name: entry.name }); -// loadPromises.push(loadPromise); -// loadPromise.then((profileDeleteResponse) => { -// if (isNullOrUndefined(profileList.get(entry.name))) { -// profileList.set(entry.type, [profileDeleteResponse.profile]); -// } else { -// profileList.set(entry.type, profileList.get(entry.type) -// .concat(profileDeleteResponse.profile)); -// } -// // if (profileDeleteResponse.success) { -// // if (isNullOrUndefined(profileList.get(entry.name))) { -// // profileList.set(entry.type, [profileDeleteResponse.profile]); -// // } -// // else { -// // profileList.set(entry.type, profileList.get(entry.type) -// // .concat(profileDeleteResponse.profile)); -// // } -// // } -// // else { -// // errors.push("Could not load the dependent profile " + entry.name + -// // " from module " + entry.type); -// // } -// }).catch((loadErr) => { -// rejectCommand(loadErr); -// }); -// } -// } -// } -// Promise.all(loadPromises).then((values) => { -// if (!shouldForce) { -// this.displayPrompts(profileList, commandParameters, errors); -// } -// else { -// this.deleteWithoutPrompts(profileList, commandParameters, errors); -// } -// }); -// }).catch((loadErr) => { -// // if (shouldForce) { -// // if (!isNullOrUndefined(profileResponse.profile)) { -// // profileList.set(profileType, [profileResponse.profile]); -// // this.deleteWithoutPrompts(profileList, commandParameters, errors); -// // } else { -// // commandParameters.response.writeErrorHeader(profileDeleteErrorHeader.message); -// // commandParameters.response.console.error( -// // unableToFindProfile.message, profileResponse.message); -// // commandParameters.response.console.error("Manual remediation is recommended."); -// // commandParameters.response.failed(); -// // } -// // } -// // else { -// commandParameters.response.appendError({ -// msg: loadErr.message, -// additionalDetails: "You can use the --force operand to " + -// "force deletion of the profile in error." -// }); -// this.rejectCommand(); -// // } -// }); -// }); -// } - -// private deleteWithoutPrompts(profileList: Map, commandParameters: IHandlerParameters, -// errors: string[]) { -// const profileModule = new ProfileManager(commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]); -// const deletePromises: Array> = []; -// const successes: string[] = []; -// profileList.forEach((profiles, module, map) => { -// for (const profileEntry of profiles) { -// const profile: IProfile = profileEntry; -// const deleteOp: Promise = profileModule.deleteProfile({profile}); -// deletePromises.push(deleteOp); -// deleteOp.then((profileDeleted) => { -// /** -// * TODO: Work this out with the new promise scheme -// */ -// // if (profileDeleted.success) { -// // // mLogger.trace(`Successfully deleted profile ${profile.profileName}`); -// // successes.push(profile.name); -// // } -// // else { -// // // mLogger.trace(`Failed to delete the profile ${profile.profileName}`); -// // errors.push(`Error deleting profile ${profileDeleted.profilePath}.`); -// // } -// }); -// } -// }); -// Promise.all(deletePromises).then((values) => { - -// if (errors.length === 0 && successes.length > 0) { -// commandParameters.response.console.log( -// profileDeletedSuccessfully.message, successes.join()); -// } -// else if (errors.length === 0 && successes.length === 0) { -// commandParameters.response.console.log(profileNotDeletedMessage.message); -// } -// else { -// commandParameters.response.appendError({ -// msg: unableToDeleteProfile.message, -// additionalDetails: TextUtils.formatMessage( -// profileDeleteErrorDetails.message, -// {errorDetails: errors.join("\n")}) -// }); -// this.rejectCommand(); -// } -// }); -// } - -// private displayPrompts(profileList: Map, commandParameters: IHandlerParameters, -// errors: string[]) { -// const prompt: any = require("prompt"); -// prompt.message = "Attention"; -// let profileCount: number = 0; -// const successes: string[] = []; - -// const profileType = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; -// const profileManager = new ProfileManager(profileType); -// const deletePromises: Array> = []; -// profileList.forEach((profiles, module, map) => { -// for (const profileEntry of profiles) { -// const theProfile: IProfile = profileEntry; -// const promptSchema = { -// properties: { -// deleteConfirmation: { -// description: `Please confirm deletion of the profile` + -// ` "${theProfile.name}". This action cannot be undone. (true/false)`, -// type: "boolean", -// pattern: /^[YyNn]+$/, -// message: "Please enter true or false to confirm the profile deletion.", -// required: true -// } -// } -// }; -// prompt.start(); -// prompt.get(promptSchema, (err: any, result: any) => { -// // this.mLogger.debug("User entered " + result.deleteConfirmation + " for the profile " + profile.profileName); -// if (result.deleteConfirmation === true) { -// // const deleteOp: Promise = profileManager.deleteProfile(profile); -// const deleteOp: Promise = profileManager.deleteProfile({ -// profile: theProfile -// }); -// deletePromises.push(deleteOp); -// deleteOp.then((profileDeleted) => { -// /** -// * TODO: work this out with the new promise scheme -// */ -// // if (profileDeleted.success) { -// // // mLogger.trace(`Successfully deleted profile ${profile.profileName}`); -// // successes.push(profile.name); -// // } -// // else { -// // // mLogger.trace(`Failed to delete the profile ${profile.profileName}`); -// // errors.push(`Error deleting profile ${profileDeleted.profilePath}.`); -// // } -// }); -// Promise.all([deleteOp]).then((values) => { -// // do nothing -// }); -// profileCount++; -// } -// else { -// profileCount++; -// } - -// if (profileCount === profileList.get(profileType).length) { -// Promise.all(deletePromises).then((values) => { - -// if (errors.length === 0 && successes.length > 0) { -// commandParameters.response.console.log(profileDeletedSuccessfully.message, successes.join()); -// } -// else if (errors.length === 0 && successes.length === 0) { -// commandParameters.response.console.log(profileNotDeletedMessage.message); -// } -// else { -// commandParameters.response.appendError({ -// msg: unableToDeleteProfile.message, -// additionalDetails: TextUtils.formatMessage( -// profileDeleteErrorDetails.message, -// {errorDetails: errors.join("\n")}) -// }); -// this.rejectCommand(); -// } -// }); -// prompt.stop(); -// } -// }); -// } -// }); -// } -// } - diff --git a/packages/imperative/src/imperative/src/profiles/handlers/SetDefaultProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/SetDefaultProfilesHandler.ts deleted file mode 100644 index 7cdb46ea20..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/SetDefaultProfilesHandler.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { Imperative } from "../../Imperative"; -import { ProfilesConstants } from "../../../../profiles"; -import { ICommandHandler, IHandlerParameters } from "../../../../cmd"; -import { Constants } from "../../../../constants"; -/** - * Handler for the auto generated commands to set the default profile for a type - * The default profile is loaded when no specific profile name is specified - */ -export default class SetDefaultProfilesHandler implements ICommandHandler { - /** - * process the set default profile command arguments - * @return {Promise}: The promise to fulfill when complete. - */ - public process(commandParameters: IHandlerParameters): Promise { - return new Promise((commandComplete, commandRejected) => { - /** - * Get the loaded module for the command being issued and set the default profile. - */ - const profileType: string = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - const profileSpecified: string = commandParameters.arguments[Constants.PROFILE_NAME_OPTION]; - let invoked: boolean = false; - try { - Imperative.api.profileManager(profileType).setDefault(profileSpecified); - commandParameters.response.console.log(`The default profile for ${profileType} set to ` + - `${profileSpecified}`); - } catch (error) { - const err: string = `Error occurred while setting default profile for ` + - `${profileType}.\n${error.message}`; - commandParameters.response.console.error(err); - invoked = true; - commandRejected(); - } - - // Fulfill the promise - if (!invoked) { - commandComplete(); - } - }); - } - -} diff --git a/packages/imperative/src/imperative/src/profiles/handlers/ShowDependenciesProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/ShowDependenciesProfilesHandler.ts deleted file mode 100644 index 338699071a..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/ShowDependenciesProfilesHandler.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ICommandHandler, IHandlerParameters } from "../../../../cmd"; - -/** - * Handler for the auto-generated show dependencies command - */ -export default class ShowDependenciesProfilesHandler implements ICommandHandler { - - /** - * The process command handler for the "show dependencies" command. - * @return {Promise}: The promise to fulfill when complete. - */ - public process(commandParameters: IHandlerParameters): Promise { - return new Promise((commandComplete) => { - - // Do nothing - // Need for this minimized by list --verbose - commandComplete(); - }); - } -} diff --git a/packages/imperative/src/imperative/src/profiles/handlers/UpdateProfilesHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/UpdateProfilesHandler.ts deleted file mode 100644 index 6ec64af53f..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/UpdateProfilesHandler.ts +++ /dev/null @@ -1,62 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { overroteProfileMessage, profileUpdatedSuccessfullyAndPath, profileReviewMessage } from "../../../../messages"; -import { Imperative } from "../../Imperative"; -import { IProfileUpdated, ProfilesConstants } from "../../../../profiles"; -import { ICommandHandler, IHandlerParameters } from "../../../../cmd"; -import { Constants } from "../../../../constants"; -import { TextUtils } from "../../../../utilities"; - -/** - * Handler for the auto-generated update profile commands - * Allows the user to simply update an existing configuration profile - */ -export default class UpdateProfilesHandler implements ICommandHandler { - /** - * The process command handler for the "update profile" command. - * @return {Promise}: The promise to fulfill when complete. - */ - public async process(commandParameters: IHandlerParameters): Promise { - - /** - * Invoke the modules profile creator. - */ - const profileType = commandParameters.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - const profileSpecified: string = commandParameters.arguments[Constants.PROFILE_NAME_OPTION]; - let profileUpdated: IProfileUpdated; - - try { - profileUpdated = await Imperative.api.profileManager(profileType).update({ - name: profileSpecified, - args: commandParameters.arguments, - merge: true - }); - } catch (error) { - // profileIO error is thrown when calling old profile functions in team config mode. - commandParameters.response.console.error( - "An error occurred trying to update a profile.\n" + error.message - ); - return; - } - - commandParameters.response.console.log(overroteProfileMessage.message, { - profileOption: commandParameters.arguments[Constants.PROFILE_NAME_OPTION] - }); - commandParameters.response.console.log(profileUpdatedSuccessfullyAndPath.message); - commandParameters.response.console.log(profileUpdated.path); - commandParameters.response.console.log(""); - commandParameters.response.console.log(TextUtils.prettyJson(profileUpdated.profile, - undefined, undefined, "\n")); - commandParameters.response.console.log(profileReviewMessage.message); - - } -} diff --git a/packages/imperative/src/imperative/src/profiles/handlers/ValidateProfileHandler.ts b/packages/imperative/src/imperative/src/profiles/handlers/ValidateProfileHandler.ts deleted file mode 100644 index f435403304..0000000000 --- a/packages/imperative/src/imperative/src/profiles/handlers/ValidateProfileHandler.ts +++ /dev/null @@ -1,130 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { isNullOrUndefined } from "util"; -import { CliProfileManager, ICommandHandler, IHandlerParameters } from "../../../../cmd"; -import { IImperativeError, ImperativeError } from "../../../../error"; -import { Imperative } from "../../../index"; -import { - IProfileValidationPlan, - IProfileValidationReport, - IProfileValidationTask, - ProfilesConstants, - ProfileValidator -} from "../../../../profiles"; -import { Logger } from "../../../../logger"; -import { ImperativeConfig } from "../../../../utilities"; - -/** - * Generic handler for validating a profile and printing a report in response - */ -export default class ValidateProfileHandler implements ICommandHandler { - /** - * Get an instance of the imperative logger. - * @private - * @type {Logger} - * @memberof ValidateProfileHandler - */ - private mLogger: Logger = Imperative.api.imperativeLogger; - - public async process(params: IHandlerParameters): Promise { - - const profileType = params.definition.customize[ProfilesConstants.PROFILES_COMMAND_TYPE_KEY]; - - let manager: CliProfileManager; - try { - // Extract the profile manager - manager = Imperative.api.profileManager(profileType); - } catch (error) { - // profileIO error is thrown when calling old profile functions in team config mode. - params.response.console.error( - "An error occurred trying to validate a profile.\n" + error.message - ); - return; - } - - let profileName = manager.getDefaultProfileName(); - - // if the user specified a specific profile, we can determine the name of the profile from that - if (params.arguments.profileName != null) { - profileName = params.arguments.profileName; - } - - const profileToValidate = (await manager.load({failNotFound: true, name: profileName})).profile; - let plan: IProfileValidationPlan; - try { - // load the definition of the plan from the specified file path - // this will return the class definition of the plan - const planModule = Imperative.getProfileConfiguration(profileType).validationPlanModule; - plan = require(planModule); - // instantiate the plan object - plan = new (plan as any)(); - } catch (e) { - const planLoadErr: IImperativeError = { - msg: "An error was encountered trying to load the plan to validate the Zowe profile.", - additionalDetails: e.message, - causeErrors: e - }; - throw new ImperativeError(planLoadErr); - } - - // if the user just requested that we print the plan rather than actually validate the profile - if (params.arguments[ProfileValidator.PRINT_PLAN_OPTION.name]) { - - Logger.getImperativeLogger().debug("Printed plan for profile validation requested"); - params.response.console.log(Buffer.from(ProfileValidator.getTextDisplayForPlan(plan, profileToValidate, - ImperativeConfig.instance.loadedConfig.primaryTextColor))); - - const cleanTaskForJSONOutput = (task: IProfileValidationTask) => { - delete task.taskFunction; - if (!isNullOrUndefined(task.dependentTasks)) { - for (const dependent of task.dependentTasks) { - cleanTaskForJSONOutput(dependent); - } - } - }; - // add the object version of the plan to the JSON response, without the task functions - // since they can't be printed - for (const task of plan.tasks) { - cleanTaskForJSONOutput(task); - } - params.response.data.setObj(plan); - return; - } - let report: IProfileValidationReport; - try { - const promise = ProfileValidator.validate(profileToValidate, - plan, ImperativeConfig.instance.loadedConfig.productDisplayName); - params.response.progress.startBar({task: promise.progress}); - report = await promise; - params.response.data.setObj(report); - const reportText = Buffer.from(ProfileValidator.getTextDisplayForReport(report, plan, - ImperativeConfig.instance.loadedConfig.productDisplayName, - ImperativeConfig.instance.loadedConfig.primaryTextColor, - profileName, - profileType)); - params.response.console.log(reportText); - } catch (validateError) { - const unexpectedError: IImperativeError = { - msg: "Encountered an unexpected exception " + - "while validating your profile. ", - additionalDetails: validateError.message, - causeErrors: validateError - }; - params.response.console.error("Failed to validate profile due to unexpected exception"); - throw new ImperativeError(unexpectedError); - } - if (report.overallResult !== "OK") { - throw new ImperativeError({msg: "The profile validation was not successful"}); - } - } - -} diff --git a/packages/imperative/src/messages/src/CoreMessages.ts b/packages/imperative/src/messages/src/CoreMessages.ts index d70be82fc8..ba325e230a 100644 --- a/packages/imperative/src/messages/src/CoreMessages.ts +++ b/packages/imperative/src/messages/src/CoreMessages.ts @@ -33,317 +33,10 @@ export const unexpectedCommandPreparationError: IMessageDefinition = { message: "An unexpected command preparation error occurred:" }; -export const unableToLoadRequestedProfilesError: IMessageDefinition = { - message: "Command processing cannot continue: Unable to load requested or default profiles." -}; - -export const unexpectedProfileLoadError: IMessageDefinition = { - message: "An unexpected profile load error occurred:" -}; - -export const profileLoadError: IMessageDefinition = { - message: `Error loading {{type}} profile: {{profileName}}.\n\n` + - `Additional Details:\n\n` -}; - -export const unexpectedProfilesLoadError: IMessageDefinition = { - message: "An unexpected error occurred while loading requested profiles:\n" -}; - export const syntaxErrorHeader: IMessageDefinition = { message: `\nSyntax Error` }; -export const createProfilesCommandSummary: IMessageDefinition = { - message: `Create new configuration profiles`, -}; - -export const createProfilesCommandDesc: IMessageDefinition = { - message: `${createProfilesCommandSummary.message}.`, -}; - -export const createProfileCommandSummary: IMessageDefinition = { - message: `Create a {{type}} profile`, -}; - -export const createProfileOptionDesc: IMessageDefinition = { - message: `Specifies the name of the new {{type}} profile. ` + - `You can load this profile by using the name on commands that support the ` + - `"--{{type}}-profile" option.` -}; - -export const listProfileLoadedModulesOptionDesc: IMessageDefinition = { - message: `List {{type}} ` + - ` profiles that are loaded as part of normal command execution. ` + - `This will show you the default profiles being loaded.` -}; - -export const listProfileVerboseOptionDesc: IMessageDefinition = { - message: `List {{type}} ` + - ` profiles and their contents. ` + - `All profile details will be printed as part of command output.` -}; - -export const listProfileExample: IMessageDefinition = { - message: `List profiles of type {{type}}` -}; - -export const listProfileExampleShowContents: IMessageDefinition = { - message: `List profiles of type {{type}} and display their contents` -}; - -export const deleteProfileNameDesc: IMessageDefinition = { - message: `Specifies the name of the {{type}} ` + - ` profile to be deleted. ` + - `You can also load this profile by using the name on commands that support the ` + - `"--{{typeOption}}" option.` -}; - - -export const deleteProfileExample: IMessageDefinition = { - message: `Delete a {{type}} profile named {{name}}` -}; - - -export const validateProfileNameDesc: IMessageDefinition = { - message: `Specifies the name of the {{type}} ` + - ` profile to be validated. ` + - `If the --print-plan-only option is specified, then only a plan to validate the specified profile will be displayed.` -}; - - -export const selectProfileNameDesc: IMessageDefinition = { - message: `Specifies the name of the {{type}} ` + - ` - profile to be used with this command. ` + - `To see profiles that can be validated, issue the list action for this module. ` + - `You can also load this profile by using the name on commands that support the ` + - `"--{{typeOption}}" option.` -}; - - -export const createProfileOptionOverwriteDesc: IMessageDefinition = { - message: `Overwrite the {{type}} profile when a profile of the same name exists.` -}; - -export const createProfileDisableDefaultsDesc: IMessageDefinition = { - message: `Disable populating profile values of undefined properties with default values.` -}; - -export const deleteProfilesCommandSummary: IMessageDefinition = { - message: `Delete existing profiles` -}; - -export const deleteProfilesCommandDesc: IMessageDefinition = { - message: `${deleteProfilesCommandSummary.message}.` -}; - -export const deleteProfileForceOptionDesc: IMessageDefinition = { - message: `Force deletion of profile, and dependent profiles if specified. No prompt will be displayed before ` + - `deletion occurs.` -}; - -export const deleteProfileActionDesc: IMessageDefinition = { - message: `Delete a {{type}} profile.` -}; - -export const deleteProfileCommandDesc: IMessageDefinition = { - message: `Delete a {{type}} profile.` + - ` You must specify a profile name to be deleted. To find a list of available profiles for deletion,` + - ` issue the profiles list command. By default, you will be prompted to confirm the profile removal.`, -}; - -export const deleteProfileDepsDesc: IMessageDefinition = { - message: `Set to true to delete all dependent profiles along with the {{type}} profile.` + - `If set to true, a list of dependent profiles will be shown along with a confirmation prompt before the ` + - `deletions occur. If set to false, only the {{type}} profile specified will be deleted.` -}; - -export const showDependenciesCommandDesc: IMessageDefinition = { - message: `View all profiles which may be used within a selected group.`, -}; - -export const listProfileCommandSummary: IMessageDefinition = { - message: `List existing profiles`, -}; - -export const listProfileCommandDesc: IMessageDefinition = { - message: `List profiles of the type {{type}}.`, -}; - -export const listProfilesFoundMessage: IMessageDefinition = { - message: `The following profiles were found of the type "{{type}}":`, -}; - -export const listProfilesNotFoundMessage: IMessageDefinition = { - message: `No profiles were found of the type "{{type}}".`, -}; - -export const validateProfileCommandSummary: IMessageDefinition = { - message: `Test the validity of a profile`, -}; - -export const validateProfileGroupDesc: IMessageDefinition = { - message: `Test the validity of your profiles.`, -}; -export const validateProfileCommandDesc: IMessageDefinition = { - message: `Test the validity of a {{type}} profile.`, -}; - -export const validateProfileOptionDesc: IMessageDefinition = { - message: `Validate the state of a group.`, -}; - -export const detailProfileCommandDesc: IMessageDefinition = { - message: `Show details of a profile of a selected type.`, -}; -export const updateProfileActionDesc: IMessageDefinition = { - message: `Update a {{type}} profile.`, -}; - -export const updateProfileCommandSummary: IMessageDefinition = { - message: `Update existing profiles`, -}; - -export const updateProfileCommandDesc: IMessageDefinition = { - message: `Update a {{type}} profile. ` + - `You can update any property present within the profile configuration. The updated profile ` + - `will be printed so that you can review the result of the updates.`, -}; - -export const listGroupWithOnlyProfilesSummary: IMessageDefinition = { - message: `List the {{type}} profiles loaded` -}; - -export const listGroupWithOnlyProfilesDefinition: IMessageDefinition = { - message: `List the {{type}} profiles loaded.` -}; - -export const listGroupWithOnlyProfileDefaultDesc: IMessageDefinition = { - message: `Lists all known profiles for this command group. ` + - `When you issue a command that requires a profile or set of ` + - `profiles, said profiles are loaded by default (or according to override options on the command). You can use this ` + - `command to review your configured profiles, and verify your default profile set.` -}; - -export const listGroupWithOnlyProfileCommandSummary: IMessageDefinition = { - message: `List {{type}} loaded profiles` -}; - -export const listGroupWithOnlyProfileSetDesc: IMessageDefinition = { - message: `To set the default profiles, use the " ` + - `{{type}} ${Constants.DEFAULT_SET_GROUP} ${Constants.DEFAULT_SET_PROFILE_OBJECT}" command.` -}; - -export const setProfileActionSummary: IMessageDefinition = { - message: `Set which profiles are loaded by default` -}; - -export const setProfileActionDesc: IMessageDefinition = { - message: `${setProfileActionSummary.message}.` -}; - -export const setGroupWithOnlyProfilesSummary: IMessageDefinition = { - message: `Set the default profiles for the {{type}} group` -}; - -export const setGroupWithOnlyProfilesCommandDesc: IMessageDefinition = { - message: `The {{type}} set ${Constants.DEFAULT_SET_PROFILE_OBJECT} command allows you to set the default profiles for ` + - `this command group. When a {{type}} command is issued and no profile override options are ` + - `specified, the default profiles for the command group are automatically loaded for the command based on the ` + - `commands profile requirements.` -}; - -export const setProfileOptionDesc: IMessageDefinition = { - message: `Specify a - profile for default usage within the {{type}} group. ` + - `When you issue commands within the {{type}} group without a profile specified as part of the command, the default ` + - `will be loaded instead.` -}; - -export const setProfileExample: IMessageDefinition = { - message: `Set the default profile for type {{type}} to the profile named '{{name}}'` -}; - -export const setGroupWithOnlyProfilesListDesc: IMessageDefinition = { - message: `To view the default profiles, use the " ` + - `{{type}} ${Constants.DEFAULT_LIST_GROUP} ${Constants.DEFAULT_LIST_PROFILE_OBJECT}" command.` -}; - - -export const profileCreatedSuccessfullyAndPath: IMessageDefinition = { - message: `Profile created successfully! Path:` -}; - -export const profileUpdatedSuccessfullyAndPath: IMessageDefinition = { - message: `Profile updated successfully! Path:` -}; - -export const profileReviewMessage: IMessageDefinition = { - message: "Review the created profile and edit if necessary using the profile update command." -}; - -export const profileCreateErrorHeader: IMessageDefinition = { - message: "Profile Create Error" -}; - -export const unableToCreateProfile: IMessageDefinition = { - message: "Unable to create the requested profile." -}; - -export const profileCreateErrorDetails: IMessageDefinition = { - message: "Error Details: {{errorDetails}}" -}; -export const profileNotDeletedMessage: IMessageDefinition = { - message: "No profiles were deleted." -}; - -export const profileDeletedSuccessfully: IMessageDefinition = { - message: "Successfully deleted the following profile(s): " -}; - -export const profileDeleteErrorHeader: IMessageDefinition = { - message: "Profile Deletion Error" -}; - -export const unableToDeleteProfile: IMessageDefinition = { - message: "Not all requested profiles could be deleted." -}; - -export const unableToFindProfile: IMessageDefinition = { - message: "Could not find or load the supplied profile name. Error details: " -}; - -export const profileDeleteErrorDetails: IMessageDefinition = { - message: "Error Details: {{errorDetails}}" -}; - -export const overroteProfileMessage: IMessageDefinition = { - message: "Overwrote existing profile for {{profileOption}}." -}; - -export const profileDesc: IMessageDefinition = { - message: `Configuration profiles are loaded based on the requirements ` + - `of the command:` -}; - -export const locateProfilesDesc: IMessageDefinition = { - message: `Configuration profiles are located and used by searching in the following order,` + - ` ending the search when a profile is found:` -}; - -export const profileCreatedSuccessfully: IMessageDefinition = { - message: `Profile created successfully.` -}; - -export const unexpectedProfileCreationError: IMessageDefinition = { - message: `An unexpected profile creation error occurred: \n{{unexpectedError}}` -}; - -export const unexpectedProfileUpdateError: IMessageDefinition = { - message: `An unexpected profile update error occurred: \n{{unexpectedError}}` -}; - export const authCategorySummary: IMessageDefinition = { message: `Connect to token-based authentication services` }; diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.constructor.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.constructor.unit.test.ts deleted file mode 100644 index 44732265b2..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.constructor.unit.test.ts +++ /dev/null @@ -1,251 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../src/utils/ProfileIO"); -import { ImperativeError } from "../../error/src/ImperativeError"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { APPLE_PROFILE_TYPE, FRUIT_BASKET_BAD_DIR, FRUIT_BASKET_WORSE, MANGO_PROFILE_TYPE, ONLY_APPLE, TEST_PROFILE_ROOT_DIR } from "./TestConstants"; -import { BasicProfileManager } from "../src/BasicProfileManager"; -import { IProfileTypeConfiguration } from "../src/doc/config/IProfileTypeConfiguration"; - -// UnitTestUtils.replaceIt(); - -describe("Basic Profile Manager Constructor", () => { - it("should detect no parms when instantiating", () => { - let error; - try { - const prof = new BasicProfileManager(undefined); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the profile directory is undefined", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: undefined, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the profile directory is blank", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: " ", - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that no type configuration is supplied", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: undefined, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain("An error occurred collecting all configurations from the profile root directory"); - }); - - it("should detect that the type configuration is an empty array", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: [], - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain("An error occurred collecting all configurations from the profile root directory"); - }); - - it("should detect if the type is undefined", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: undefined, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect if the type is blank", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: " ", - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that a type not found within the configurations", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: "bad_apple", - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain( - "Expect Error: Could not locate the profile type configuration for \"bad_apple\" within the input configuration list passed." - ); - }); - - it("should allow us to instantiate the cli profile manager", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - TestLogger.info("Profile Manager Created"); - } catch (e) { - error = e; - TestLogger.error(e); - } - expect(error).toBeUndefined(); - }); - - it("should detect that a schema definition document is attempting to overload 'type'", () => { - const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); - copy[0].schema.properties.type = {type: "boolean"}; - let caughtError; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (error) { - caughtError = error; - } - expect(caughtError).toBeUndefined(); - }); - - it("should detect that a schema definition document is attempting to overload 'name'", () => { - const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); - copy[0].schema.properties.name = {type: "boolean"}; - let caughtError; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (error) { - caughtError = error; - } - expect(caughtError).toBeUndefined(); - }); - - it("should detect that a schema definition document is attempting to overload 'dependencies'", () => { - const copy: IProfileTypeConfiguration[] = JSON.parse(JSON.stringify(ONLY_APPLE)); - copy[0].schema.properties.dependencies = {type: "boolean"}; - let caughtError; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (error) { - caughtError = error; - } - expect(caughtError).toBeUndefined(); - }); - - it("should allow instantiation if the meta doesn't have a default", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR + FRUIT_BASKET_WORSE, - type: MANGO_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - } - expect(error).toBeUndefined(); - }); - - it("should detect ill-formed meta profile configurations", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR + FRUIT_BASKET_BAD_DIR, - type: MANGO_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.delete.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.delete.unit.test.ts deleted file mode 100644 index 594859a70b..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.delete.unit.test.ts +++ /dev/null @@ -1,215 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - - -jest.mock("../src/utils/ProfileIO"); -import { BasicProfileManager } from "../src/BasicProfileManager"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { IProfileDeleted } from "../src/doc/response/IProfileDeleted"; -import { inspect } from "util"; -import { - APPLE_PROFILE_TYPE, - ONLY_APPLE, - STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; - - -describe("Basic Profile Manager Delete", () => { - it("should detect that no parms are supplied", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete(undefined); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect the parms did not specify a name", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - const parms = {name: "mulberry"}; - delete parms.name; - response = await prof.delete(parms); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect the parms specified a blank name", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - const parms = {name: " "}; - - response = await prof.delete(parms); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect there is no profile of the specified name to delete", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete({name: "red_delicious"}); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a delete where the profile to delete is marked as a dependency of another profile", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete({name: "good_apple", rejectIfDependency: true}); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to handle an error thrown by delete/unlink", async () => { - const prof: any = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const profile = { - name: "mackintosh_error_apple" - }; - prof.loadProfile = jest.fn().mockReturnValue({profile}); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete(profile); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to delete a profile", async () => { - const prof: any = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const profile = { - name: "mackintosh_apple" - }; - prof.loadProfile = jest.fn().mockReturnValue({profile}); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete(profile); - TestLogger.info("Delete Full Response:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - expect(response.path).toContain("mackintosh_apple.yaml"); - }); - - it("should detect that the profile to delete is marked as a dependency of another profile, but allow delete if specified", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileDeleted; - try { - response = await prof.delete({name: "good_apple", rejectIfDependency: false}); - TestLogger.error(response.message); - TestLogger.error("Delete response - should not get here:\n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - expect(response.path).toContain("good_apple.yaml"); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.load.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.load.unit.test.ts deleted file mode 100644 index 5530004561..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.load.unit.test.ts +++ /dev/null @@ -1,488 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { inspect } from "util"; -import { IProfileLoaded } from "../../profiles/src/doc/response/IProfileLoaded"; -import { - APPLE_PROFILE_TYPE, - APPLE_TWO_REQ_DEP_BANANA_AND_STRAWBERRIES, - APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE, - APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP, - BLUEBERRY_PROFILE_TYPE, - ONLY_APPLE, - ONLY_BLUEBERRY, - ONLY_ORANGE, - ORANGE_PROFILE_TYPE, - STRAWBERRY_AND_APPLE_NO_DEP, - STRAWBERRY_PROFILE_TYPE, - STRAWBERRY_WITH_OPTIONAL_APPLE_DEPENDENCY, - STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; -import { BasicProfileManager } from "../src/BasicProfileManager"; - -jest.mock("../src/utils/ProfileIO"); - -describe("Basic Profile Manager Load", () => { - it("should detect missing parms", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const response = await prof.load(undefined); - TestLogger.error(response.message); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect parms with a missing profile name", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const response = await prof.load({}); - TestLogger.error(response.message); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a load request if the profile is not found", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const response = await prof.load({name: "missing_apple"}); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a load request if the profile loaded does not conform to the schema", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const response = await prof.load({name: "misshapen_apple"}); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should handle a read error", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const response = await prof.load({name: "throw_the_apple"}); - TestLogger.error(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow the load of a well formed profile", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "good_apple"}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.error(error.message); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - expect(response.profile).toMatchSnapshot(); - expect(response.dependenciesLoaded).toBe(false); - expect(response.dependencyLoadResponses).toEqual([]); - expect(response.name).toBe("good_apple"); - expect(response.type).toBe(APPLE_PROFILE_TYPE); - }); - - it("should load the default if requested", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_BLUEBERRY, - type: BLUEBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({loadDefault: true}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - expect(response.profile).toMatchSnapshot(); - expect(response.dependenciesLoaded).toBe(false); - expect(response.dependencyLoadResponses).toEqual([]); - expect(response.name).toBe("sweet_blueberry"); - expect(response.type).toBe(BLUEBERRY_PROFILE_TYPE); - }); - - it("should fail if the default doesn't exist", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_ORANGE, - type: ORANGE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({loadDefault: true}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail the request if no profile name is specified and default profile is set but not found", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_ORANGE, - type: ORANGE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - // Mock having a default profile set - prof.getDefaultProfileName = jest.fn(() => { - return "missing_orange"; - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({loadDefault: true, failNotFound: false}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeDefined(); - expect(error.message).toContain("does not exist"); - expect(error.message).toMatchSnapshot(); - }); - - it("should not fail the request if 'fail not found' is false and the profile was not found", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_ORANGE, - type: ORANGE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({loadDefault: true, failNotFound: false}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.info(error.message); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - expect(response.profile).toBeUndefined(); - }); - - it("should load a profile with one dependency", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "sweet_strawberry"}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.error(error.message); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should load a profile with two dependencies", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_AND_STRAWBERRIES, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "apples_and_strawberries_and_bananas"}); - TestLogger.info(response.message); - } catch (e) { - error = e; - TestLogger.error(error.message); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should load a profile with two dependencies, one of which has it's own dependency", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "apples_and_grapes_and_strawberries_and_bananas"}); - TestLogger.info(response.message); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should fail a profile load with two dependencies, one of which has it's own dependency with an error", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "apples_and_grapes_with_error_and_strawberries_and_bananas"}); - TestLogger.info(response.message); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a profile load with two dependencies, one of which has it's own dependency which is not found", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "apples_and_grapes_not_found_and_strawberries_and_bananas"}); - TestLogger.info(response.message); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a profile load with two dependencies, one of which has it's own dependency that is circular", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "apple_has_circular"}); - TestLogger.error(response.message); - TestLogger.error("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to load all profiles for all types", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_AND_APPLE_NO_DEP, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded[]; - try { - response = await prof.loadAll(); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should allow us to load a profile with an optional dependency that is not specified", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_OPTIONAL_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "strawberry_no_apple"}); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should not allow us to load a profile with an optional dependency and the optional dependency doesn't exist", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_OPTIONAL_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "strawberry_not_found_apple"}); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to load a profile where an optional dependency doesn't exist (but fail not found is false)", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_OPTIONAL_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "strawberry_not_found_apple", failNotFound: false}); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should fail a load if the profile doesn't have the required dependencies listed when loaded", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileLoaded; - try { - response = await prof.load({name: "strawberry_no_apple"}); - TestLogger.info("Load response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.error(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.merge.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.merge.unit.test.ts deleted file mode 100644 index 02d4f9c1a1..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.merge.unit.test.ts +++ /dev/null @@ -1,183 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../src/utils/ProfileIO"); - -import { PROFILE_TYPE } from "../../../__tests__/src/packages/profiles/src/constants/BasicProfileManagerTestConstants"; -import { BasicProfileManager } from "../src/BasicProfileManager"; -import { - APPLE_PROFILE_TYPE, - GRAPE_PROFILE_TYPE, - ONLY_APPLE, - STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { IProfile, ProfileIO } from "../"; -import { inspect } from "util"; - -// UnitTestUtils.replaceIt(); -const testLogger = TestLogger.getTestLogger(); -describe("Basic Profile Manager - Merge", () => { - it("Should be able to merge two simple profiles together, " + - "with the new profile taking precedence for same-name fields", () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - const profileA: IProfile = {type: APPLE_PROFILE_TYPE, name: "first", description: "first apple", age: 5}; - const profileB: IProfile = {type: APPLE_PROFILE_TYPE, name: "second", rotten: true}; - const merged = prof.mergeProfiles(profileA, profileB); - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.name).toEqual(profileB.name); - expect(merged.rotten).toEqual(profileB.rotten); - expect(merged.description).toEqual(profileA.description); - expect(merged.age).toEqual(profileA.age); - }); - - it("should merge dependencies on profiles, while deleting duplicates", () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: PROFILE_TYPE.STRAWBERRY, - logger: TestLogger.getTestLogger() - }); - - const profileA: IProfile = { - type: PROFILE_TYPE.STRAWBERRY, name: "first", - dependencies: [{type: APPLE_PROFILE_TYPE, name: "old_apple"}, {type: GRAPE_PROFILE_TYPE, name: "old_grape"}] - }; - const profileB: IProfile = { - type: PROFILE_TYPE.STRAWBERRY, - name: "second", - dependencies: [{type: APPLE_PROFILE_TYPE, name: "new_apple"}] - }; - const merged = prof.mergeProfiles(profileA, profileB); - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.dependencies.length).toEqual(2); // should still have two dependencies - let appleDependency: any; - let grapeDependency: any; - for (const dependency of merged.dependencies) { - if (dependency.type === APPLE_PROFILE_TYPE) { - appleDependency = dependency; - } - else if (dependency.type === GRAPE_PROFILE_TYPE) { - grapeDependency = dependency; - } - } - expect(appleDependency).toBeDefined(); - expect(grapeDependency).toBeDefined(); - expect(appleDependency.name).toEqual(profileB.dependencies[0].name); - expect(grapeDependency.name).toEqual(profileA.dependencies[1].name); - }); - - it("should replace array type profile fields (other than dependencies) with newer versions of the array" + - "rather than merging them (merging them makes it impossible to specify new values when" + - "updating profiles via CLI) ", () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: PROFILE_TYPE.STRAWBERRY, - logger: TestLogger.getTestLogger() - }); - const oldProfile: IProfile = { - type: PROFILE_TYPE.STRAWBERRY, name: "first", - myArrayVariable: ["old_value1", "oldValue2"], - // test that the array replacement still works on deeply nested fields - hasNestedArray: {hasNestedArray: {hasNestedArray: ["old_value1", "old_value2"]}} - }; - const newProfile: IProfile = { - type: PROFILE_TYPE.STRAWBERRY, - name: "first", - myArrayVariable: ["new_value1", "new_value2", "new_value3"], - hasNestedArray: {hasNestedArray: {hasNestedArray: ["new_value1", "new_value2", "new_value3", "new_value4"]}} - }; - const merged = prof.mergeProfiles(oldProfile, newProfile); - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.myArrayVariable.length).toEqual(newProfile.myArrayVariable.length); - for (const oldValue of oldProfile.myArrayVariable) { - expect(merged.myArrayVariable.indexOf(oldValue)).toEqual(-1); - } - - for (const oldValue of oldProfile.hasNestedArray.hasNestedArray.hasNestedArray) { - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.indexOf(oldValue)).toEqual(-1); - } - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.length).toEqual(newProfile.hasNestedArray.hasNestedArray.hasNestedArray.length); - expect(merged.hasNestedArray).toEqual(newProfile.hasNestedArray); - }); - - it("should merge on update if \"merge\" is specified on the parms", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: [{ - type: PROFILE_TYPE.STRAWBERRY, - schema: { - type: "object", - title: "test profile for updating on merging", - description: "ditto", - properties: { - myArrayVariable: { - type: "array" - }, - hasNestedArray: { - type: "object" - } - } - } - }], - type: PROFILE_TYPE.STRAWBERRY, - logger: TestLogger.getTestLogger() - }); - const profileA = { - type: PROFILE_TYPE.STRAWBERRY, name: "first", - myArrayVariable: ["old_value1", "oldValue2"], - // test that the array replacement still works on deeply nested fields - hasNestedArray: {hasNestedArray: {hasNestedArray: ["old_value1", "old_value2"]}}, - }; - ProfileIO.writeProfile = jest.fn((path: string, profile: any) => { - // do nothing - }); - ProfileIO.exists = jest.fn((path: string) => { - return path.indexOf("meta") === -1 ? path : undefined; - }); - ProfileIO.readProfileFile = jest.fn((filePath: string, type: string) => { - if (type === PROFILE_TYPE.STRAWBERRY) { - return profileA; - } - else { - return { - type: "apple", - name: "thing" - }; - } - }); - const profileB: IProfile = { - myArrayVariable: ["new_value1", "new_value2", "new_value3"], - hasNestedArray: {hasNestedArray: {hasNestedArray: ["new_value1", "new_value2", "new_value3", "new_value4"]}}, - }; - const updateResult = await prof.update({name: "first", profile: profileB, merge: true}); - const merged = updateResult.profile; - testLogger.info("Merged profile result: " + inspect(merged, {depth: null})); - expect(merged.myArrayVariable.length).toEqual(profileB.myArrayVariable.length); - for (const oldValue of profileA.myArrayVariable) { - expect(merged.myArrayVariable.indexOf(oldValue)).toEqual(-1); - } - - for (const oldValue of profileA.hasNestedArray.hasNestedArray.hasNestedArray) { - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.indexOf(oldValue)).toEqual(-1); - } - expect(merged.hasNestedArray.hasNestedArray.hasNestedArray.length).toEqual(profileB.hasNestedArray.hasNestedArray.hasNestedArray.length); - expect(merged.hasNestedArray).toEqual(profileB.hasNestedArray); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.save.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.save.unit.test.ts deleted file mode 100644 index 793ecf51bf..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.save.unit.test.ts +++ /dev/null @@ -1,625 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../src/utils/ProfileIO"); -import { ImperativeError } from "../../error/src/ImperativeError"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { ISaveProfile } from "../src/doc/parms/ISaveProfile"; -import { inspect } from "util"; -import { IProfileSaved } from "../src/doc/response/IProfileSaved"; -import { - APPLE_BAN_UNKNOWN, - APPLE_PROFILE_TYPE, - APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP, - BANANA_PROFILE_TYPE, - MANGO_PROFILE_TYPE, - ONLY_APPLE, - ONLY_MANGO, - STRAWBERRY_PROFILE_TYPE, - STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; -import { BasicProfileManager } from "../src/BasicProfileManager"; - -const BAD_SAMPLE_SAVE_PARMS: ISaveProfile = { - name: "bad_apple", - type: "bad_apple", - profile: {} -}; - -const GOOD_SAMPLE_SAVE_PARMS: ISaveProfile = { - name: "apple", - type: STRAWBERRY_PROFILE_TYPE, - profile: {} -}; - -describe("Basic Profile Manager Save", () => { - it("should detect missing parameters", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const response = await prof.save(undefined); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect missing profile", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const parms = {name: "bad_apple", profile: {}}; - delete parms.profile; - const response = await prof.save(parms as any); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a type mismatch when saving a profile", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const response = await prof.save(BAD_SAMPLE_SAVE_PARMS); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain( - "Expect Error: Could not locate the profile type configuration for \"strawberry\" within the input configuration list passed." - ); - }); - - it("should detect a blank name when creating a profile", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const copy = JSON.parse(JSON.stringify({ - name: " ", - profile: {} - })); - const response = await prof.save(copy); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a missing name when creating a profile", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const copy = JSON.parse(JSON.stringify({ - profile: {} - })); - const response = await prof.save(copy); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect if the meta name was specified as the profile name", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const copy = JSON.parse(JSON.stringify({ - name: APPLE_PROFILE_TYPE + "_meta", - profile: {} - })); - const response = await prof.save(copy); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the dependencies are not an array", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {}; - profile.dependencies = {}; - response = await prof.save({name: "bad_apple", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the dependencies are present, but name is missing", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {}; - profile.dependencies = [{type: STRAWBERRY_PROFILE_TYPE}]; - response = await prof.save({name: "bad_apple", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the dependencies are present, but type is missing", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {}; - profile.dependencies = [{name: "bad_strawberry"}]; - response = await prof.save({name: "bad_apple", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that a profile requires a dependency of a certain type", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {description: "A bunch of rotten strawberries", amount: 30}; - response = await prof.save({name: "bad_strawberry", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect all missing required fields on the schema", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = { - dependencies: [{type: APPLE_PROFILE_TYPE, name: "bad_apple"}] - }; - response = await prof.save({name: "bad_strawberry", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a type mismatch from the schema for strings", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {description: true, rotten: true, age: 100}; - response = await prof.save({name: "bad_apple", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a type mismatch from the schema for booleans", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - const profile: any = {description: "A nasty apple", rotten: "yes", age: 100}; - response = await prof.save({name: "bad_apple", profile} as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a save request if the file already exists and overwrite is false", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: "A nasty apple", rotten: true, age: 100}; - const saveResponse = await prof.save({ - name: "old_apple", - profile, - overwrite: false - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a save request if an error is thrown by write file", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: "A nasty apple", rotten: true, age: 100}; - const saveResponse = await prof.save({ - name: "throw_the_apple", - profile, - overwrite: true - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should fail a save request if there is an error writing the meta file", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_MANGO, - type: MANGO_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: "A nasty mango", peeled: true}; - const saveResponse = await prof.save({ - name: "bad_mango", - profile, - overwrite: true, - updateDefault: true - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to save a well-formed profile", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let saveResponse: IProfileSaved; - try { - const profile: any = {description: "A tasty apple", rotten: false, age: 1}; - saveResponse = await prof.save({ - name: "good_apple", - profile, - overwrite: true - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeUndefined(); - expect(saveResponse.message).toContain('Profile ("good_apple" of type "apple") successfully written:'); - expect(saveResponse.profile).toMatchSnapshot(); - }); - - it("should allow us to save a profile with a dependency", async () => { - const copy = JSON.parse(JSON.stringify(STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY)); - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: copy, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let saveResponse: IProfileSaved; - try { - const strawberry: any = { - type: STRAWBERRY_PROFILE_TYPE, - amount: 10000, - description: "Strawberries covered in chocolate.", - dependencies: [ - { - type: APPLE_PROFILE_TYPE, - name: "tasty_apples" - } - ] - }; - saveResponse = await prof.save({ - name: "chocolate_covered", - profile: strawberry, - overwrite: true - } as any); - } catch (e) { - error = e; - } - expect(error).toBeUndefined(); - expect(saveResponse.message).toContain('Profile ("chocolate_covered" of type "strawberry") successfully written:'); - expect(saveResponse.profile).toMatchSnapshot(); - }); - - it("should not allow us to overwrite a profile if overwrite false (or not specified)", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let saveResponse: IProfileSaved; - try { - const profile: any = {description: "A tasty apple", rotten: false, age: 1}; - saveResponse = await prof.save({ - name: "good_apple", - profile, - } as any); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should not allow a save with a circular dependency", async () => { - const copy = JSON.parse(JSON.stringify(APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP)); - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: copy, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - response = await prof.save({ - name: "apple_with_two_req_dep_circular", - type: APPLE_PROFILE_TYPE, - profile: { - age: 1000, - description: "An old apple", - rotten: true, - dependencies: [ - { - type: STRAWBERRY_PROFILE_TYPE, - name: "chocolate_covered" - }, - { - type: BANANA_PROFILE_TYPE, - name: "banana_with_grape_dep" - } - ] - }, - overwrite: true - }); - TestLogger.error(response.message); - TestLogger.error("Save response: \n" + inspect(response, {depth: null})); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should not allow a save with no contents", async () => { - const copy = JSON.parse(JSON.stringify(ONLY_APPLE)); - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: copy, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileSaved; - try { - response = await prof.save({ - name: "no_apple_core", - profile: {}, - overwrite: true - } as any); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should not allow us to save a profile that lists dependencies of types that were not defined", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let saveResponse: IProfileSaved; - try { - const profile: any = { - description: "A tasty apple", - rotten: false, - age: 1, - dependencies: [{name: "bad_pear", type: "pear"}] - }; - saveResponse = await prof.save({ - name: "good_apple", - profile, - overwrite: true - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeDefined(); - expect(error.message).toContain("Could not save the profile, because one or more dependencies is invalid or does not exist."); - expect(error.message).toContain( - "Load Error Details: Expect Error: Could not locate the profile type " + - "configuration for \"pear\" within the input configuration list passed." - ); - }); - - it("should fail a save request if a profile has more properties than defined on the schema", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_BAN_UNKNOWN, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let saveResponse: IProfileSaved; - try { - const profile: any = { - description: "A tasty apple", - rotten: false, - age: 1, - seedless: false - }; - saveResponse = await prof.save({ - name: "tasty_apple", - profile, - overwrite: true - } as any); - } catch (e) { - error = e; - TestLogger.info(e.message); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.unit.test.ts deleted file mode 100644 index 2e4bfa13b7..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.unit.test.ts +++ /dev/null @@ -1,284 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -jest.mock("../src/utils/ProfileIO"); -import { ImperativeError } from "../../error/src/ImperativeError"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { IProfileLoaded } from "../../profiles/src/doc/response/IProfileLoaded"; -import { - APPLE_PROFILE_TYPE, - APPLE_TWO_REQ_DEP_BANANA_AND_STRAWBERRIES, - BLUEBERRY_PROFILE_TYPE, - FRUIT_BASKET_DIR, - ONLY_APPLE, - ONLY_BLUEBERRY, - STRAWBERRY_AND_APPLE_NO_DEP, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; -import { BasicProfileManager } from "../src/BasicProfileManager"; -// UnitTestUtils.replaceIt(); - -describe("Basic Profile Manager", () => { - it("should detect no parms when instantiating", () => { - let error; - try { - const prof = new BasicProfileManager(undefined); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the profile directory is undefined", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: undefined, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the profile directory is blank", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: " ", - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that no type configuration is supplied", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: undefined, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain("An error occurred collecting all configurations from the profile root directory"); - }); - - it("should detect that the type configuration is an empty array", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: [], - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain("An error occurred collecting all configurations from the profile root directory"); - }); - - it("should detect if the type is undefined", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: undefined, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect if the type is blank", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: " ", - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that a type not found within the configurations", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: "bad_apple", - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain( - "Expect Error: Could not locate the profile type configuration for \"bad_apple\" within the input configuration list passed." - ); - }); - - it("should allow us to instantiate the cli profile manager", () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - TestLogger.info("Profile Manager Created"); - } catch (e) { - error = e; - TestLogger.error(e); - } - expect(error).toBeUndefined(); - }); - - it("should load all profiles", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_AND_APPLE_NO_DEP, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let responses: IProfileLoaded[]; - try { - responses = await prof.loadAll(); - } catch (e) { - error = e; - TestLogger.error(e); - } - expect(error).toBeUndefined(); - expect(responses).toMatchSnapshot(); - }); - - it("should detect ill formed profiles during a load all", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: APPLE_TWO_REQ_DEP_BANANA_AND_STRAWBERRIES, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let responses: IProfileLoaded[]; - try { - responses = await prof.loadAll(); - } catch (e) { - error = e; - TestLogger.error(e); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should create an instance and read all configurations from the meta files", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR + FRUIT_BASKET_DIR, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - expect(prof.configurations).toMatchSnapshot(); - }); - - it("should fail a create if no configurations and passed and none can be read from disk", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - } catch (e) { - error = e; - } - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to set the default in the meta profile", () => { - let error; - let response; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_BLUEBERRY, - type: BLUEBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - response = prof.setDefault("tart_blueberry"); - } catch (e) { - error = e; - TestLogger.error(e); - } - expect(error).toBeUndefined(); - expect(response).toMatchSnapshot(); - }); - - it("should fail a request to set the default if the profile is not found", () => { - let error; - let response; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_BLUEBERRY, - type: BLUEBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - response = prof.setDefault("bad_blueberry"); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - expect(response).toBeUndefined(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.update.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.update.unit.test.ts deleted file mode 100644 index 9071658896..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.update.unit.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { BasicProfileManager } from "../src/BasicProfileManager"; -import { APPLE_PROFILE_TYPE, ONLY_APPLE, TEST_PROFILE_ROOT_DIR } from "./TestConstants"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { IProfileUpdated } from "../src/doc/response/IProfileUpdated"; - -jest.mock("../src/utils/ProfileIO"); - - -describe("Basic Profile Manager Update", () => { - it("should detect missing parameters", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileUpdated; - try { - response = await prof.update(undefined); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect missing name parameter", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileUpdated; - try { - response = await prof.update({}); - } catch (e) { - error = e; - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); - - it("should allow us to update a profile", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileUpdated; - try { - response = await prof.update({ - name: "good_apple", - profile: { - rotten: false, - description: "Getting older, but still good.", age: 2 - } - } as any); - } catch (e) { - error = e; - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/BasicProfileManager.validate.unit.test.ts b/packages/imperative/src/profiles/__tests__/BasicProfileManager.validate.unit.test.ts deleted file mode 100644 index 9d4b548882..0000000000 --- a/packages/imperative/src/profiles/__tests__/BasicProfileManager.validate.unit.test.ts +++ /dev/null @@ -1,308 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { BasicProfileManager } from "../src/BasicProfileManager"; -import { TestLogger } from "../../../__tests__/src/TestLogger"; -import { IProfileValidated } from "../src/doc/response/IProfileValidated"; -import { - APPLE_PROFILE_TYPE, - ONLY_APPLE, - STRAWBERRY_PROFILE_TYPE, - STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - TEST_PROFILE_ROOT_DIR -} from "./TestConstants"; -import { ImperativeError } from "../../error/src/ImperativeError"; - -jest.mock("../src/utils/ProfileIO"); - -describe("Basic Profile Manager Validate", () => { - it("should detect undefined parms", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const response = await prof.validate(undefined); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a type mismatch", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const response = await prof.validate({profile: {}} as any); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toContain( - "Expect Error: Could not locate the profile type configuration for \"strawberry\" within the input configuration list passed." - ); - }); - - it("should detect a that we are attempting to use the meta name", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const copy = JSON.parse(JSON.stringify({ - name: APPLE_PROFILE_TYPE + "_meta", - profile: {} - })); - const response = await prof.validate(copy); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect a missing profile name", async () => { - let error; - try { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - const response = await prof.validate({profile: {}} as any); - } catch (e) { - error = e; - TestLogger.info(e); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the dependencies are not an array", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {}; - profile.dependencies = {}; - const response = await prof.validate({name: "bad_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should detect that the dependencies are present, but name is missing", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {}; - profile.dependencies = [{type: STRAWBERRY_PROFILE_TYPE}]; - const response = await prof.validate({name: "bad_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect that the dependencies are present, but type is missing", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {}; - profile.dependencies = [{name: "bad_strawberry"}]; - const response = await prof.validate({name: "bad_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect that a profile requires a dependency of a certain type", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: "A bunch of rotten strawberries", amount: 30}; - const response = await prof.validate({name: "bad_strawberry", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect all missing required fields on the schema", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: STRAWBERRY_WITH_REQUIRED_APPLE_DEPENDENCY, - type: STRAWBERRY_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = { - - dependencies: [{type: APPLE_PROFILE_TYPE, name: "bad_apple"}] - }; - const response = await prof.validate({name: "bad_strawberry", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect a type mismatch from the schema for strings", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: true, rotten: true, age: 100}; - const response = await prof.validate({name: "bad_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should be able to detect a type mismatch from the schema for booleans", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - try { - const profile: any = {description: "A nasty apple", rotten: "yes", age: 100}; - const response = await prof.validate({name: "bad_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error instanceof ImperativeError).toBe(true); - expect(error.message).toMatchSnapshot(); - }); - - it("should validate a well formed profile successfully", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileValidated; - try { - const profile: any = {description: "A tasty apple", rotten: false, age: 1}; - response = await prof.validate({name: "good_apple", profile}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeUndefined(); - expect(response.message).toMatchSnapshot(); - }); - - it("should fail a save request if a profile has more properties than defined on the schema", async () => { - const prof = new BasicProfileManager({ - profileRootDirectory: TEST_PROFILE_ROOT_DIR, - typeConfigurations: ONLY_APPLE, - type: APPLE_PROFILE_TYPE, - logger: TestLogger.getTestLogger() - }); - - let error; - let response: IProfileValidated; - try { - const profile: any = { - description: "A tasty apple", - rotten: false, - age: 1, - seedless: false - }; - response = await prof.validate({name: "good_apple", profile, strict: true}); - } catch (e) { - error = e; - TestLogger.info(error); - } - expect(error).toBeDefined(); - expect(error.message).toMatchSnapshot(); - }); -}); diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.constructor.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.constructor.unit.test.ts.snap deleted file mode 100644 index 5676ecfca2..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.constructor.unit.test.ts.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Constructor should detect if the type is blank 1`] = `"Expect Error: No profile type supplied on the profile manager parameters."`; - -exports[`Basic Profile Manager Constructor should detect if the type is undefined 1`] = `"Expect Error: No profile type supplied on the profile manager parameters."`; - -exports[`Basic Profile Manager Constructor should detect ill-formed meta profile configurations 1`] = `"An error occurred collecting all configurations from the profile root directory \\"__tests__/__results__/test_profiles/root/dir//FRUIT_BAD_BASKET/\\". Please supply the configurations on the profile manager constructor parameters OR initialize the profile manager environment. Details: Expect Error: A meta profile of type \\"mango\\", does NOT supply a configuration."`; - -exports[`Basic Profile Manager Constructor should detect no parms when instantiating 1`] = `"Expect Error: Profile Manager input parms not supplied."`; - -exports[`Basic Profile Manager Constructor should detect that the profile directory is blank 1`] = `"Expect Error: No profile root directory supplied on the profile manager parameters"`; - -exports[`Basic Profile Manager Constructor should detect that the profile directory is undefined 1`] = `"Expect Error: No profile root directory supplied on the profile manager parameters"`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.delete.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.delete.unit.test.ts.snap deleted file mode 100644 index 4836b56f89..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.delete.unit.test.ts.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Delete should detect there is no profile of the specified name to delete 1`] = `"Profile \\"red_delicious\\" of type \\"apple\\" does not exist."`; - -exports[`Basic Profile Manager Delete should be able to delete a profile 1`] = `"Profile \\"mackintosh_apple\\" of type \\"apple\\" deleted successfully."`; - -exports[`Basic Profile Manager Delete should be able to detect the parms specified a blank name 1`] = `"Expect Error: A delete was requested for profile type \\"apple\\", but the name specified is undefined or blank."`; - -exports[`Basic Profile Manager Delete should be able to handle an error thrown by delete/unlink 1`] = `"IO ERROR DELETING THE APPLE"`; - -exports[`Basic Profile Manager Delete should detect that no parms are supplied 1`] = `"Expect Error: A delete was requested for profile type \\"apple\\", but no parameters were specified."`; - -exports[`Basic Profile Manager Delete should detect that the profile to delete is marked as a dependency of another profile, but allow delete if specified 1`] = `"Profile \\"good_apple\\" of type \\"apple\\" deleted successfully."`; - -exports[`Basic Profile Manager Delete should detect the parms did not specify a name 1`] = `"Expect Error: A delete was requested for profile type \\"apple\\", but the name specified is undefined or blank."`; - -exports[`Basic Profile Manager Delete should fail a delete where the profile to delete is marked as a dependency of another profile 1`] = ` -"The profile specified for deletion (\\"good_apple\\" of type \\"apple\\") is marked as a dependency for profiles: -Name: \\"strawberry_and_apple\\" Type: \\"strawberry\\"" -`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.load.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.load.unit.test.ts.snap deleted file mode 100644 index 0bca82d962..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.load.unit.test.ts.snap +++ /dev/null @@ -1,339 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Load should allow the load of a well formed profile 1`] = `"Profile \\"good_apple\\" of type \\"apple\\" loaded successfully."`; - -exports[`Basic Profile Manager Load should allow the load of a well formed profile 2`] = ` -Object { - "age": 1, - "description": "A tasty apple", - "rotten": false, -} -`; - -exports[`Basic Profile Manager Load should allow us to load a profile where an optional dependency doesn't exist (but fail not found is false) 1`] = ` -Object { - "dependenciesLoaded": true, - "dependencyLoadResponses": Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": false, - "message": "Profile \\"missing_apple\\" of type \\"apple\\" was not found, but the request indicated to ignore \\"not found\\" errors. The profile returned is undefined.", - "name": "missing_apple", - "type": "apple", - }, - ], - "failNotFound": false, - "message": "Profile \\"strawberry_not_found_apple\\" of type \\"strawberry\\" loaded successfully.", - "name": "strawberry_not_found_apple", - "profile": Object { - "amount": 1000, - "dependencies": Array [ - Object { - "name": "missing_apple", - "type": "apple", - }, - ], - "description": "Tasty", - }, - "type": "strawberry", -} -`; - -exports[`Basic Profile Manager Load should allow us to load a profile with an optional dependency that is not specified 1`] = ` -Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"strawberry_no_apple\\" of type \\"strawberry\\" loaded successfully.", - "name": "strawberry_no_apple", - "profile": Object { - "amount": 1000, - "description": "Tasty", - }, - "type": "strawberry", -} -`; - -exports[`Basic Profile Manager Load should allow us to load all profiles for all types 1`] = ` -Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"good_apple\\" of type \\"apple\\" loaded successfully.", - "name": "good_apple", - "profile": Object { - "age": 1, - "description": "A tasty apple", - "rotten": false, - }, - "type": "apple", - }, - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"tasty_apples\\" of type \\"apple\\" loaded successfully.", - "name": "tasty_apples", - "profile": Object { - "age": 1, - "description": "tasty", - "rotten": false, - }, - "type": "apple", - }, - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"strawberry_and_apple\\" of type \\"strawberry\\" loaded successfully.", - "name": "strawberry_and_apple", - "profile": Object { - "amount": 1000, - "dependencies": Array [ - Object { - "name": "good_apple", - "type": "apple", - }, - ], - "description": "Tasty", - }, - "type": "strawberry", - }, -] -`; - -exports[`Basic Profile Manager Load should detect missing parms 1`] = `"Expect Error: Profile load requested for type \\"apple\\", but no parameters supplied."`; - -exports[`Basic Profile Manager Load should detect parms with a missing profile name 1`] = `"Expect Error: A profile load was requested for type \\"apple\\", but no profile name was specified."`; - -exports[`Basic Profile Manager Load should fail a load if the profile doesn't have the required dependencies listed when loaded 1`] = `"Profile validation error during load of profile \\"strawberry_no_apple\\" of type \\"strawberry\\". Error Details: Profile type \\"strawberry\\" specifies a required dependency of type \\"apple\\" on the \\"strawberry\\" profile type configuration document. A dependency of type \\"apple\\" was NOT listed on the input profile."`; - -exports[`Basic Profile Manager Load should fail a load request if the profile is not found 1`] = `"Profile \\"missing_apple\\" of type \\"apple\\" does not exist."`; - -exports[`Basic Profile Manager Load should fail a load request if the profile loaded does not conform to the schema 1`] = ` -"Profile validation error during load of profile \\"misshapen_apple\\" of type \\"apple\\". Error Details: Errors located in profile \\"misshapen_apple\\" of type \\"apple\\": -profile requires property \\"rotten\\" -profile requires property \\"age\\" -" -`; - -exports[`Basic Profile Manager Load should fail a profile load with two dependencies, one of which has it's own dependency that is circular 1`] = ` -"An error occurred while loading the dependencies of profile \\"apple_has_circular\\" of type \\"apple\\". Dependency load list: -Type: \\"strawberry\\" Name: \\"chocolate_covered\\" -Type: \\"banana\\" Name: \\"banana_with_grape_dep\\" - -Error Details: An error occurred while loading the dependencies of profile \\"banana_with_grape_dep\\" of type \\"banana\\". Dependency load list: -Type: \\"grape\\" Name: \\"grape_with_banana_circular_dep\\" - -Error Details: An error occurred while loading the dependencies of profile \\"grape_with_banana_circular_dep\\" of type \\"grape\\". Dependency load list: -Type: \\"banana\\" Name: \\"banana_with_grape_dep\\" - -Error Details: A circular profile dependency was detected. Profile \\"banana_with_grape_dep\\" of type \\"banana\\" either points directly to itself OR a dependency of this profile points to this profile." -`; - -exports[`Basic Profile Manager Load should fail a profile load with two dependencies, one of which has it's own dependency which is not found 1`] = ` -"An error occurred while loading the dependencies of profile \\"apples_and_grapes_not_found_and_strawberries_and_bananas\\" of type \\"apple\\". Dependency load list: -Type: \\"strawberry\\" Name: \\"chocolate_strawberries\\" -Type: \\"banana\\" Name: \\"bananas_error_and_grapes\\" - -Error Details: An error occurred while loading the dependencies of profile \\"bananas_error_and_grapes\\" of type \\"banana\\". Dependency load list: -Type: \\"grape\\" Name: \\"no_grapes\\" - -Error Details: Profile \\"no_grapes\\" of type \\"grape\\" does not exist." -`; - -exports[`Basic Profile Manager Load should fail a profile load with two dependencies, one of which has it's own dependency with an error 1`] = ` -"An error occurred while loading the dependencies of profile \\"apples_and_grapes_with_error_and_strawberries_and_bananas\\" of type \\"apple\\". Dependency load list: -Type: \\"strawberry\\" Name: \\"chocolate_strawberries\\" -Type: \\"banana\\" Name: \\"bananas_and_error_grapes\\" - -Error Details: An error occurred while loading the dependencies of profile \\"bananas_and_error_grapes\\" of type \\"banana\\". Dependency load list: -Type: \\"grape\\" Name: \\"bad_grapes\\" - -Error Details: Profile validation error during load of profile \\"bad_grapes\\" of type \\"grape\\". Error Details: Errors located in profile \\"bad_grapes\\" of type \\"grape\\": -profile requires property \\"description\\" -profile requires property \\"color\\" -" -`; - -exports[`Basic Profile Manager Load should fail if the default doesn't exist 1`] = `"No default profile set for type \\"orange\\"."`; - -exports[`Basic Profile Manager Load should fail the request if no profile name is specified and default profile is set but not found 1`] = ` -"Your default profile named missing_orange does not exist for type orange. -To change your default profile, run \\"undefined profiles set-default orange \\"." -`; - -exports[`Basic Profile Manager Load should handle a read error 1`] = `"Read error!"`; - -exports[`Basic Profile Manager Load should load a profile with one dependency 1`] = ` -Object { - "dependenciesLoaded": true, - "dependencyLoadResponses": Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"good_apple\\" of type \\"apple\\" loaded successfully.", - "name": "good_apple", - "profile": Object { - "age": 1, - "description": "A tasty apple", - "rotten": false, - }, - "type": "apple", - }, - ], - "failNotFound": true, - "message": "Profile \\"sweet_strawberry\\" of type \\"strawberry\\" loaded successfully.", - "name": "sweet_strawberry", - "profile": Object { - "amount": 1000, - "dependencies": Array [ - Object { - "name": "good_apple", - "type": "apple", - }, - ], - "description": "Super sweet strawberries", - }, - "type": "strawberry", -} -`; - -exports[`Basic Profile Manager Load should load a profile with two dependencies 1`] = ` -Object { - "dependenciesLoaded": true, - "dependencyLoadResponses": Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"chocolate_strawberries\\" of type \\"strawberry\\" loaded successfully.", - "name": "chocolate_strawberries", - "profile": Object { - "amount": 1000, - "description": "chocolate covered", - }, - "type": "strawberry", - }, - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"bundle_of_bananas\\" of type \\"banana\\" loaded successfully.", - "name": "bundle_of_bananas", - "profile": Object { - "bundle": true, - }, - "type": "banana", - }, - ], - "failNotFound": true, - "message": "Profile \\"apples_and_strawberries_and_bananas\\" of type \\"apple\\" loaded successfully.", - "name": "apples_and_strawberries_and_bananas", - "profile": Object { - "age": 1, - "dependencies": Array [ - Object { - "name": "chocolate_strawberries", - "type": "strawberry", - }, - Object { - "name": "bundle_of_bananas", - "type": "banana", - }, - ], - "description": "A tasty apple", - "rotten": false, - }, - "type": "apple", -} -`; - -exports[`Basic Profile Manager Load should load a profile with two dependencies, one of which has it's own dependency 1`] = ` -Object { - "dependenciesLoaded": true, - "dependencyLoadResponses": Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"chocolate_strawberries\\" of type \\"strawberry\\" loaded successfully.", - "name": "chocolate_strawberries", - "profile": Object { - "amount": 1000, - "description": "chocolate covered", - }, - "type": "strawberry", - }, - Object { - "dependenciesLoaded": true, - "dependencyLoadResponses": Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"green_grapes\\" of type \\"grape\\" loaded successfully.", - "name": "green_grapes", - "profile": Object { - "color": "green", - "description": "Super tasty grapes", - }, - "type": "grape", - }, - ], - "failNotFound": true, - "message": "Profile \\"bananas_and_grapes\\" of type \\"banana\\" loaded successfully.", - "name": "bananas_and_grapes", - "profile": Object { - "bundle": true, - "dependencies": Array [ - Object { - "name": "green_grapes", - "type": "grape", - }, - ], - }, - "type": "banana", - }, - ], - "failNotFound": true, - "message": "Profile \\"apples_and_grapes_and_strawberries_and_bananas\\" of type \\"apple\\" loaded successfully.", - "name": "apples_and_grapes_and_strawberries_and_bananas", - "profile": Object { - "age": 1, - "dependencies": Array [ - Object { - "name": "chocolate_strawberries", - "type": "strawberry", - }, - Object { - "name": "bananas_and_grapes", - "type": "banana", - }, - ], - "description": "A tasty apple", - "rotten": false, - }, - "type": "apple", -} -`; - -exports[`Basic Profile Manager Load should load the default if requested 1`] = `"Profile \\"sweet_blueberry\\" of type \\"blueberry\\" loaded successfully."`; - -exports[`Basic Profile Manager Load should load the default if requested 2`] = ` -Object { - "tart": false, -} -`; - -exports[`Basic Profile Manager Load should not allow us to load a profile with an optional dependency and the optional dependency doesn't exist 1`] = ` -"An error occurred while loading the dependencies of profile \\"strawberry_not_found_apple\\" of type \\"strawberry\\". Dependency load list: -Type: \\"apple\\" Name: \\"missing_apple\\" - -Error Details: Profile \\"missing_apple\\" of type \\"apple\\" does not exist." -`; - -exports[`Basic Profile Manager Load should not fail the request if 'fail not found' is false and the profile was not found 1`] = `"Profile \\"default was requested\\" of type \\"orange\\" was not found, but the request indicated to ignore \\"not found\\" errors. The profile returned is undefined."`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.save.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.save.unit.test.ts.snap deleted file mode 100644 index 950e4aadfa..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.save.unit.test.ts.snap +++ /dev/null @@ -1,91 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Save should allow us to save a profile with a dependency 1`] = ` -Object { - "amount": 10000, - "dependencies": Array [ - Object { - "name": "tasty_apples", - "type": "apple", - }, - ], - "description": "Strawberries covered in chocolate.", - "type": "strawberry", -} -`; - -exports[`Basic Profile Manager Save should allow us to save a well-formed profile 1`] = ` -Object { - "age": 1, - "description": "A tasty apple", - "rotten": false, -} -`; - -exports[`Basic Profile Manager Save should detect a blank name when creating a profile 1`] = `"Expect Error: Required parameter 'name' must not be blank"`; - -exports[`Basic Profile Manager Save should detect a missing name when creating a profile 1`] = `"Expect Error: A request was made to save a profile of type \\"apple\\", but no name was supplied."`; - -exports[`Basic Profile Manager Save should detect a type mismatch from the schema for booleans 1`] = ` -"Errors located in profile \\"bad_apple\\" of type \\"apple\\": -rotten is not of a type(s) boolean -" -`; - -exports[`Basic Profile Manager Save should detect a type mismatch from the schema for strings 1`] = ` -"Errors located in profile \\"bad_apple\\" of type \\"apple\\": -description is not of a type(s) string -" -`; - -exports[`Basic Profile Manager Save should detect all missing required fields on the schema 1`] = ` -"Errors located in profile \\"bad_strawberry\\" of type \\"strawberry\\": -profile requires property \\"description\\" -profile requires property \\"amount\\" -" -`; - -exports[`Basic Profile Manager Save should detect if the meta name was specified as the profile name 1`] = `"Expect Error: You cannot specify \\"apple_meta\\" as a profile name. This profile name is reserved for internal Imperative usage."`; - -exports[`Basic Profile Manager Save should detect missing parameters 1`] = `"Expect Error: A request was made to save a profile of type \\"apple\\", but no parameters were supplied."`; - -exports[`Basic Profile Manager Save should detect missing profile 1`] = `"Expect Error: A request was made to save a profile of type \\"apple\\", but no profile was supplied."`; - -exports[`Basic Profile Manager Save should detect that a profile requires a dependency of a certain type 1`] = `"Profile type \\"strawberry\\" specifies a required dependency of type \\"apple\\" on the \\"strawberry\\" profile type configuration document. A dependency of type \\"apple\\" was NOT listed on the input profile."`; - -exports[`Basic Profile Manager Save should detect that the dependencies are not an array 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but it is NOT an array (ill-formed)"`; - -exports[`Basic Profile Manager Save should detect that the dependencies are present, but name is missing 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but an entry does not contain \\"name\\"."`; - -exports[`Basic Profile Manager Save should detect that the dependencies are present, but type is missing 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but an entry does not contain \\"type\\"."`; - -exports[`Basic Profile Manager Save should fail a save request if a profile has more properties than defined on the schema 1`] = ` -"Errors located in profile \\"tasty_apple\\" of type \\"apple\\": -profile is not allowed to have the additional property \\"seedless\\" -" -`; - -exports[`Basic Profile Manager Save should fail a save request if an error is thrown by write file 1`] = `"Write file unexpected failure"`; - -exports[`Basic Profile Manager Save should fail a save request if the file already exists and overwrite is false 1`] = `"Profile \\"old_apple\\" of type \\"apple\\" already exists and overwrite was NOT specified."`; - -exports[`Basic Profile Manager Save should fail a save request if there is an error writing the meta file 1`] = `"Error writing the meta file"`; - -exports[`Basic Profile Manager Save should not allow a save with a circular dependency 1`] = ` -"Could not save the profile, because one or more dependencies is invalid or does not exist. -Load Error Details: An error occurred while loading the dependencies of profile \\"apple_with_two_req_dep_circular\\" of type \\"apple\\". Dependency load list: -Type: \\"strawberry\\" Name: \\"chocolate_covered\\" -Type: \\"banana\\" Name: \\"banana_with_grape_dep\\" - -Error Details: An error occurred while loading the dependencies of profile \\"banana_with_grape_dep\\" of type \\"banana\\". Dependency load list: -Type: \\"grape\\" Name: \\"grape_with_banana_circular_dep\\" - -Error Details: An error occurred while loading the dependencies of profile \\"grape_with_banana_circular_dep\\" of type \\"grape\\". Dependency load list: -Type: \\"banana\\" Name: \\"banana_with_grape_dep\\" - -Error Details: A circular profile dependency was detected. Profile \\"banana_with_grape_dep\\" of type \\"banana\\" either points directly to itself OR a dependency of this profile points to this profile." -`; - -exports[`Basic Profile Manager Save should not allow a save with no contents 1`] = `"The profile passed (name \\"no_apple_core\\" of type \\"apple\\") does not contain any content."`; - -exports[`Basic Profile Manager Save should not allow us to overwrite a profile if overwrite false (or not specified) 1`] = `"Profile \\"good_apple\\" of type \\"apple\\" already exists and overwrite was NOT specified."`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.unit.test.ts.snap deleted file mode 100644 index 81eeb957bb..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.unit.test.ts.snap +++ /dev/null @@ -1,162 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager should allow us to set the default in the meta profile 1`] = `"Default profile for type \\"blueberry\\" set to \\"tart_blueberry\\"."`; - -exports[`Basic Profile Manager should create an instance and read all configurations from the meta files 1`] = ` -Array [ - Object { - "schema": Object { - "description": "The simple apple configuration", - "properties": Object { - "age": Object { - "type": "number", - }, - "description": Object { - "type": "string", - }, - "rotten": Object { - "type": "boolean", - }, - }, - "required": Array [ - "description", - "rotten", - "age", - ], - "title": "The simple apple configuration", - "type": "object", - }, - "type": "apple", - }, - Object { - "schema": Object { - "description": "The simple strawberry configuration", - "properties": Object { - "amount": Object { - "type": "number", - }, - "description": Object { - "type": "string", - }, - }, - "required": Array [ - "description", - "amount", - ], - "title": "The simple strawberry configuration", - "type": "object", - }, - "type": "strawberry", - }, - Object { - "schema": Object { - "description": "The simple banana configuration", - "properties": Object { - "bundle": Object { - "type": "boolean", - }, - "description": Object { - "type": "string", - }, - }, - "required": Array [ - "bundle", - ], - "title": "The simple banana configuration", - "type": "object", - }, - "type": "banana", - }, - Object { - "schema": Object { - "description": "The simple banana configuration", - "properties": Object { - "color": Object { - "type": "string", - }, - "description": Object { - "type": "string", - }, - }, - "required": Array [ - "description", - "color", - ], - "title": "The simple banana configuration", - "type": "object", - }, - "type": "grape", - }, -] -`; - -exports[`Basic Profile Manager should detect if the type is blank 1`] = `"Expect Error: No profile type supplied on the profile manager parameters."`; - -exports[`Basic Profile Manager should detect if the type is undefined 1`] = `"Expect Error: No profile type supplied on the profile manager parameters."`; - -exports[`Basic Profile Manager should detect ill formed profiles during a load all 1`] = ` -"An error occurred attempting to load all profiles of every type. Load List: -Loading \\"good_apple\\" of type \\"apple\\" -Loading \\"tasty_apples\\" of type \\"apple\\" -Loading \\"strawberry_and_apple\\" of type \\"strawberry\\" -Error Details: \\"Profile validation error during load of profile \\"good_apple\\" of type \\"apple\\". Error Details: Profile type \\"apple\\" specifies a required dependency of type \\"strawberry\\" on the \\"apple\\" profile type configuration document. A dependency of type \\"strawberry\\" was NOT listed on the input profile.\\"" -`; - -exports[`Basic Profile Manager should detect no parms when instantiating 1`] = `"Expect Error: Profile Manager input parms not supplied."`; - -exports[`Basic Profile Manager should detect that the profile directory is blank 1`] = `"Expect Error: No profile root directory supplied on the profile manager parameters"`; - -exports[`Basic Profile Manager should detect that the profile directory is undefined 1`] = `"Expect Error: No profile root directory supplied on the profile manager parameters"`; - -exports[`Basic Profile Manager should fail a create if no configurations and passed and none can be read from disk 1`] = `"An error occurred collecting all configurations from the profile root directory \\"__tests__/__results__/test_profiles/root/dir/\\". Please supply the configurations on the profile manager constructor parameters OR initialize the profile manager environment. Details: No profile configurations found. Please initialize the profile manager OR supply the configurations to the profile manager."`; - -exports[`Basic Profile Manager should fail a request to set the default if the profile is not found 1`] = `"Cannot update default profile for type \\"blueberry\\". The profile name specified (\\"bad_blueberry\\") does not exist. Please create before attempting to set the default."`; - -exports[`Basic Profile Manager should load all profiles 1`] = ` -Array [ - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"good_apple\\" of type \\"apple\\" loaded successfully.", - "name": "good_apple", - "profile": Object { - "age": 1, - "description": "A tasty apple", - "rotten": false, - }, - "type": "apple", - }, - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"tasty_apples\\" of type \\"apple\\" loaded successfully.", - "name": "tasty_apples", - "profile": Object { - "age": 1, - "description": "tasty", - "rotten": false, - }, - "type": "apple", - }, - Object { - "dependenciesLoaded": false, - "dependencyLoadResponses": Array [], - "failNotFound": true, - "message": "Profile \\"strawberry_and_apple\\" of type \\"strawberry\\" loaded successfully.", - "name": "strawberry_and_apple", - "profile": Object { - "amount": 1000, - "dependencies": Array [ - Object { - "name": "good_apple", - "type": "apple", - }, - ], - "description": "Tasty", - }, - "type": "strawberry", - }, -] -`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.update.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.update.unit.test.ts.snap deleted file mode 100644 index a5731ad124..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.update.unit.test.ts.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Update should allow us to update a profile 1`] = `"Profile \\"good_apple\\" of type \\"apple\\" updated successfully."`; - -exports[`Basic Profile Manager Update should detect missing name parameter 1`] = `"Expect Error: An update for a profile of type \\"apple\\" was requested, but no name was specified."`; - -exports[`Basic Profile Manager Update should detect missing parameters 1`] = `"Expect Error: An update for a profile of type \\"apple\\" was requested, but no parameters were specified."`; diff --git a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.validate.unit.test.ts.snap b/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.validate.unit.test.ts.snap deleted file mode 100644 index 0b4000e40e..0000000000 --- a/packages/imperative/src/profiles/__tests__/__snapshots__/BasicProfileManager.validate.unit.test.ts.snap +++ /dev/null @@ -1,42 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Basic Profile Manager Validate should be able to detect a type mismatch from the schema for booleans 1`] = ` -"Errors located in profile \\"bad_apple\\" of type \\"apple\\": -rotten is not of a type(s) boolean -" -`; - -exports[`Basic Profile Manager Validate should be able to detect a type mismatch from the schema for strings 1`] = ` -"Errors located in profile \\"bad_apple\\" of type \\"apple\\": -description is not of a type(s) string -" -`; - -exports[`Basic Profile Manager Validate should be able to detect all missing required fields on the schema 1`] = ` -"Errors located in profile \\"bad_strawberry\\" of type \\"strawberry\\": -profile requires property \\"description\\" -profile requires property \\"amount\\" -" -`; - -exports[`Basic Profile Manager Validate should be able to detect that a profile requires a dependency of a certain type 1`] = `"Profile type \\"strawberry\\" specifies a required dependency of type \\"apple\\" on the \\"strawberry\\" profile type configuration document. A dependency of type \\"apple\\" was NOT listed on the input profile."`; - -exports[`Basic Profile Manager Validate should be able to detect that the dependencies are present, but type is missing 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but an entry does not contain \\"type\\"."`; - -exports[`Basic Profile Manager Validate should detect a missing profile name 1`] = `"Expect Error: The profile passed does not contain a name (type: \\"apple\\") OR the name property specified is not of type \\"string\\"."`; - -exports[`Basic Profile Manager Validate should detect a that we are attempting to use the meta name 1`] = `"Expect Error: You cannot specify \\"apple_meta\\" as a profile name. This profile name is reserved for internal Imperative usage."`; - -exports[`Basic Profile Manager Validate should detect that the dependencies are not an array 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but it is NOT an array (ill-formed)"`; - -exports[`Basic Profile Manager Validate should detect that the dependencies are present, but name is missing 1`] = `"Expect Error: The profile passed (name \\"bad_apple\\" of type \\"apple\\") has dependencies as a property, but an entry does not contain \\"name\\"."`; - -exports[`Basic Profile Manager Validate should detect undefined parms 1`] = `"Expect Error: A request was made to validate a profile (of type \\"apple\\"), but no parameters were specified."`; - -exports[`Basic Profile Manager Validate should fail a save request if a profile has more properties than defined on the schema 1`] = ` -"Errors located in profile \\"good_apple\\" of type \\"apple\\": -profile is not allowed to have the additional property \\"seedless\\" -" -`; - -exports[`Basic Profile Manager Validate should validate a well formed profile successfully 1`] = `"Profile \\"good_apple\\" of type \\"apple\\" is valid."`; diff --git a/packages/imperative/src/profiles/index.ts b/packages/imperative/src/profiles/index.ts index d6732dd0eb..427dad1903 100644 --- a/packages/imperative/src/profiles/index.ts +++ b/packages/imperative/src/profiles/index.ts @@ -18,40 +18,16 @@ export * from "./src/doc/definition/IProfile"; export * from "./src/doc/definition/IProfileDependency"; export * from "./src/doc/definition/IProfileProperty"; export * from "./src/doc/definition/IProfileSchema"; -export * from "./src/doc/api/IProfileManagerFactory"; -export * from "./src/doc/parms/IDeleteProfile"; -export * from "./src/doc/parms/ILoadProfile"; export * from "./src/doc/parms/IProfileManager"; -export * from "./src/doc/parms/ISaveProfile"; -export * from "./src/doc/parms/ISaveProfileFromCliArgs"; -export * from "./src/doc/parms/ISetDefaultProfile"; -export * from "./src/doc/parms/IUpdateProfile"; -export * from "./src/doc/parms/IUpdateProfileFromCliArgs"; -export * from "./src/doc/parms/IValidateProfile"; -export * from "./src/doc/parms/IValidateProfileForCLI"; -export * from "./src/doc/parms/IValidateProfileWithSchema"; - -export * from "./src/doc/api/IProfileManagerFactory"; - -export * from "./src/doc/response/IProfileDeleted"; export * from "./src/doc/response/IProfileLoaded"; -export * from "./src/doc/response/IProfileSaved"; -export * from "./src/doc/response/IProfileUpdated"; -export * from "./src/doc/response/IProfileValidated"; export * from "./src/utils/ProfileIO"; export * from "./src/utils/ProfileUtils"; export * from "./src/utils"; -export * from "./src/validation/api/ProfileValidator"; - export * from "./src/validation/doc/IProfileValidationPlan"; export * from "./src/validation/doc/IProfileValidationReport"; export * from "./src/validation/doc/IProfileValidationTask"; export * from "./src/validation/doc/IProfileValidationTaskResult"; -export * from "./src/BasicProfileManager"; -export * from "./src/BasicProfileManagerFactory"; - -export * from "./src/abstract/AbstractProfileManagerFactory"; diff --git a/packages/imperative/src/profiles/src/BasicProfileManager.ts b/packages/imperative/src/profiles/src/BasicProfileManager.ts deleted file mode 100644 index fd24fa00e4..0000000000 --- a/packages/imperative/src/profiles/src/BasicProfileManager.ts +++ /dev/null @@ -1,279 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { AbstractProfileManager } from "./abstract/AbstractProfileManager"; -import { - IDeleteProfile, - ILoadProfile, - IProfile, - IProfileDeleted, - IProfileLoaded, - IProfileSaved, - IProfileTypeConfiguration, - IProfileUpdated, - IProfileValidated, - ISaveProfile, - IUpdateProfile, - IValidateProfileWithSchema -} from "./doc"; - -import { isNullOrUndefined } from "util"; -import { ImperativeError } from "../../error"; -import { ProfileIO } from "./utils"; - -/** - * Basic Profile Manager is the most basic implementation of the Imperative Profile Manager. In general, it invokes - * all of the utility/services from the Abstract Profile manager to load, save, delete, validate, etc. Imperative - * profiles. See the "AbstractProfileManager" header for more profile management details. - * - * The main differences between the abstract and the basic include: - * - * 1) The "loadAll()" API in the basic profile manager loads ALL profiles from all types. - * 2) The Basic Profile Manager includes the "initialize()" API, which will create all type directories and persist - * the schema in the meta files. - * - * The Basic Profile Manager can be used "stand-alone" from an Imperative CLI. The intent is to provide apps built - * using Imperative CLI's to take advantage of the profiles that the user has defined, without having to "locate" the - * configuration documents used to construct the CLI's. This is why the initialize() API persists the configuration - * documents within the meta files for each type. - * - * @export - * @class BasicProfileManager - * @extends {AbstractProfileManager} - * @template T - */ -export class BasicProfileManager extends AbstractProfileManager { - /** - * Loads all profiles from every type. Profile types are deteremined by reading all directories within the - * profile root directory. - * @returns {Promise} - The list of all profiles for every type - * @memberof BasicProfileManager - */ - public async loadAll(): Promise { - this.log.trace(`Loading all profiles...`); - // Load all the other profiles for other types - const loadTheirProfiles: any[] = []; - let loadList: string = ""; - for (const typeConfig of this.profileTypeConfigurations) { - const typeProfileManager = new BasicProfileManager({ - profileRootDirectory: this.profileRootDirectory, - typeConfigurations: this.profileTypeConfigurations, - type: typeConfig.type, - logger: this.log, - loadCounter: this.loadCounter - }); - - // Get all the profile names for the type and attempt to load every one - const names: string[] = typeProfileManager.getAllProfileNames(); - for (const name of names) { - this.log.debug(`Loading profile "${name}" of type "${typeConfig.type}".`); - loadTheirProfiles.push(typeProfileManager.load({name, failNotFound: true, loadDependencies: false})); - loadList += `\nLoading "${name}" of type "${typeConfig.type}"`; - } - } - - // Construct the full list for return - let allProfiles: IProfileLoaded[] = []; - try { - this.log.trace(`Awaiting all loads...`); - const theirProfiles = await Promise.all(loadTheirProfiles); - for (const theirs of theirProfiles) { - allProfiles = allProfiles.concat(theirs); - } - this.log.trace(`All loads complete.`); - } catch (e) { - const msg: string = `An error occurred attempting to load all profiles of every type. ` + - `Load List: ${loadList}\nError Details: "${e.message}"`; - this.log.error(msg); - throw new ImperativeError({msg}); - } - - return allProfiles; - } - - /** - * Loads all dependencies for the profile specified - returns the list in the response structure. Sub-dependencies - * are also loaded. - * @protected - * @param {string} name - the name of hte profile to load dependencies for - * @param {IProfile} profile - The profile to load dependencies. - * @param {boolean} [failNotFound=true] - Indicates that you want to avoid failing the request for "not found" errors. - * @returns {Promise} - The list of profiles loaded with all dependencies. - * @memberof BasicProfileManager - */ - protected loadDependencies(name: string, profile: IProfile, failNotFound = true): Promise { - return new Promise((dependenciesLoaded, loadFailed) => { - - // Construct a list of promises to load all profiles - const promises: Array> = []; - const responses: IProfileLoaded[] = []; - if (!isNullOrUndefined(profile.dependencies)) { - this.log.debug(`Loading dependencies for profile of "${this.profileType}".`); - let list: string = ""; - for (const dependency of profile.dependencies) { - this.log.debug(`Loading dependency "${dependency.name}" of type "${dependency.type}".`); - promises.push(new BasicProfileManager({ - profileRootDirectory: this.profileRootDirectory, - typeConfigurations: this.profileTypeConfigurations, - type: dependency.type, - logger: this.log, - loadCounter: this.loadCounter - }).load({name: dependency.name, failNotFound})); - list += `\nType: "${dependency.type}" Name: "${dependency.name}"`; - } - - // Wait for all the promises to complete - Promise.all(promises).then((loadResponses) => { - this.log.debug(`All dependencies loaded for profile of type "${this.profileType}".`); - // Append the responses for return to caller - for (const response of loadResponses) { - responses.push(response); - } - dependenciesLoaded(responses); - }).catch((loadsFailed) => { - this.log.error(`Failure to load dependencies for profile of type "${this.profileType}". ` + - `Details: ${loadsFailed.message}`); - const err: string = `An error occurred while loading the dependencies of profile ` + - `"${name}" of type "${this.profileType}". Dependency load list: ${list}\n\nError Details: ${loadsFailed.message}`; - loadFailed(new ImperativeError({msg: err, additionalDetails: loadsFailed})); - }); - } else { - this.log.trace(`Profile of type "${this.profileType}" has no dependencies.`); - dependenciesLoaded([]); - } - }); - } - - /** - * Save the profile to disk. First ensures that all dependencies are valid and writes the profile. - * @protected - * @param {ISaveProfile} parms - Save control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) - * @memberof BasicProfileManager - */ - protected async saveProfile(parms: ISaveProfile): Promise { - // Validate that the dependencies listed exist before saving - try { - this.log.debug(`Loading dependencies for profile "${parms.name}" of type "${this.profileType}", ` + - `checking if if they are valid (before save.)`); - await this.loadDependencies(parms.name, parms.profile); - } catch (e) { - throw new ImperativeError({ - msg: `Could not save the profile, because one or more dependencies is invalid or does not exist.\n` + - `Load Error Details: ${e.message}` - }); - } - - // Construct the full file path, write to disk, and return the response - this.log.info(`Saving profile "${parms.name}" of type "${this.profileType}"...`); - const path = this.constructFullProfilePath(parms.name); - ProfileIO.writeProfile(path, parms.profile); - this.log.info(`Profile "${parms.name}" of type "${this.profileType}" saved.`); - return { - path, - overwritten: parms.overwrite || false, - message: `Profile ("${parms.name}" of type "${this.profileType}") ` + - `successfully written: ${path}`, - profile: parms.profile - }; - } - - /** - * Load a profile from disk - invokes the "loadSpecificProfile" method in the abstract to perform the load. - * @protected - * @param {ILoadProfile} parms - Load control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) - * @memberof BasicProfileManager - */ - protected async loadProfile(parms: ILoadProfile): Promise { - const loadName: string = (parms.loadDefault || false) ? this.getDefaultProfileName() : parms.name; - this.log.debug(`Loading profile "${loadName}" (load default: "${parms.loadDefault}") of type "${this.profileType}".`); - return this.loadSpecificProfile(loadName, parms.failNotFound, parms.loadDependencies); - } - - /** - * Delete a profile from disk - invokes the "deleteProfileFromDisk" method in the abstract to perform the load. - * @protected - * @param {IDeleteProfile} parms - Delete control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) - * @memberof BasicProfileManager - */ - protected async deleteProfile(parms: IDeleteProfile): Promise { - this.log.trace(`Removing profile "${parms.name}" of type "${this.profileType}".`); - const path = this.deleteProfileFromDisk(parms.name); - this.log.debug(`Profile "${parms.name}" of type "${this.profileType}" successfully deleted.`); - return { - path, - message: `Profile "${parms.name}" of type "${this.profileType}" deleted successfully.` - }; - } - - /** - * Validate profile - ensures that the profile is valid against the schema and configuration document - * @protected - * @param {IValidateProfileWithSchema} parms - Validate control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) - * @memberof BasicProfileManager - */ - protected async validateProfile(parms: IValidateProfileWithSchema): Promise { - this.log.trace(`Validating profile "${parms.name}" of type "${this.profileType}"`); - // Ensure that the profile is not empty - if (this.isProfileEmpty(parms.profile)) { - throw new ImperativeError({ - msg: `The profile passed (name "${parms.name}" of type ` + - `"${this.profileType}") does not contain any content.` - }); - } - - // If the configuration indicates this profile type has required dependencies, ensure that those are specified - // on the profile object passed. - this.validateRequiredDependenciesAreSpecified(parms.profile); - - // Validate the profile against the schema - this.validateProfileAgainstSchema(parms.name, parms.profile, parms.strict); - - // Return the response - this.log.debug(`Profile "${parms.name}" of type "${this.profileType}" is valid.`); - return { - message: `Profile "${parms.name}" of type "${this.profileType}" is valid.` - }; - } - - /** - * Update a profile - Accepts the "new" version of the profile and overwrites the existing profile on disk. - * @protected - * @param {IUpdateProfile} parms - Update control params - see the interface for full details - * @returns {Promise} - Promise that is fulfilled when complete (or rejected with an Imperative Error) - * @memberof BasicProfileManager - */ - protected async updateProfile(parms: IUpdateProfile): Promise { - this.log.trace(`Saving (as part of updating) profile "${parms.name}" of type "${this.profileType}".`); - if (parms.merge) { - this.log.debug(`Profile merging was requested. Loading the old version of the profile ` + - `"${parms.name}" of type "${this.profileType}".`); - const oldProfileLoad = await this.load({name: parms.name, failNotFound: true}); - parms.profile = this.mergeProfiles(oldProfileLoad.profile, parms.profile); - this.log.debug(`Merged profile "${parms.name}" of type "${this.profileType}" with old version`); - } - const response = await this.save({ - name: parms.name, - type: this.profileType, - profile: parms.profile, - overwrite: true - }); - this.log.trace(`Save of profile "${parms.name}" of type "${this.profileType}" complete.`); - return { - path: response.path, - message: `Profile "${parms.name}" of type "${this.profileType}" updated successfully.`, - profile: response.profile - }; - } -} diff --git a/packages/imperative/src/profiles/src/BasicProfileManagerFactory.ts b/packages/imperative/src/profiles/src/BasicProfileManagerFactory.ts deleted file mode 100644 index c8695635ed..0000000000 --- a/packages/imperative/src/profiles/src/BasicProfileManagerFactory.ts +++ /dev/null @@ -1,85 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { AbstractProfileManagerFactory } from "./abstract/AbstractProfileManagerFactory"; -import { IProfileTypeConfiguration } from "./doc/config/IProfileTypeConfiguration"; -import { BasicProfileManager } from "./BasicProfileManager"; - -/** - * A basic profile mananger factory - returns instances of profile managers depending on the types passed. - * @export - * @class BasicProfileManagerFactory - * @extends {AbstractProfileManagerFactory} - */ -export class BasicProfileManagerFactory extends AbstractProfileManagerFactory { - /** - * The root directory where the profiles will be found. - * @private - * @type {string} - * @memberof BasicProfileManagerFactory - */ - private mProfilesRootDirectory: string; - - /** - * Type configurations for the basic profile manager - * @private - * @type {IProfileTypeConfiguration[]} - * @memberof BasicProfileManagerFactory - */ - private mTypeConfigurations: IProfileTypeConfiguration[]; - - /** - * Creates an instance of BasicProfileManagerFactory. - * @param {string} profilesRootDirectory - The root directory to find your profiles - * @memberof BasicProfileManagerFactory - */ - constructor(profilesRootDirectory: string, typeConfigurations?: IProfileTypeConfiguration[]) { - super(); - this.mProfilesRootDirectory = profilesRootDirectory; - this.mTypeConfigurations = typeConfigurations; - } - - /** - * Returns a new instance of the basic profile manager for the type. - * @param {string} type - the profile type to manager. - * @returns {BasicProfileManager} - The profile manager instance for the type. - * @memberof BasicProfileManagerFactory - */ - public getManager(type: string): BasicProfileManager { - return new BasicProfileManager({ - type, - profileRootDirectory: this.profilesRootDirectory, - typeConfigurations: this.typeConfigurations - }); - } - - /** - * Accessor for the profiles root directory - * @readonly - * @private - * @type {string} - * @memberof BasicProfileManagerFactory - */ - private get profilesRootDirectory(): string { - return this.mProfilesRootDirectory; - } - - /** - * Accessor for the type configurations - * @readonly - * @private - * @type {IProfileTypeConfiguration[]} - * @memberof BasicProfileManagerFactory - */ - private get typeConfigurations(): IProfileTypeConfiguration[] { - return this.mTypeConfigurations; - } -} diff --git a/packages/imperative/src/profiles/src/abstract/AbstractProfileManager.ts b/packages/imperative/src/profiles/src/abstract/AbstractProfileManager.ts deleted file mode 100644 index 36564b38b8..0000000000 --- a/packages/imperative/src/profiles/src/abstract/AbstractProfileManager.ts +++ /dev/null @@ -1,1359 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { ImperativeExpect } from "../../../expect"; -import { inspect, isNullOrUndefined, isString } from "util"; -import { Logger } from "../../../logger"; -import { ImperativeError } from "../../../error"; -import * as nodePath from "path"; -import { - IDeleteProfile, - ILoadProfile, - IMetaProfile, - IProfile, - IProfileDeleted, - IProfileDependency, - IProfileLoaded, - IProfileManager, - IProfileSaved, - IProfileSchema, - IProfileTypeConfiguration, - IProfileUpdated, - IProfileValidated, - ISaveProfile, - IUpdateProfile, - IValidateProfile, - IValidateProfileWithSchema, - ILoadAllProfiles -} from "../doc/"; -import { ProfileIO, ProfileUtils } from "../utils"; -import { ImperativeConfig } from "../../../utilities"; - -const SchemaValidator = require("jsonschema").Validator; - -/** - * The abstract profile manager contains most (if not all in some cases) methods to manage Imperative profiles. Profiles - * are user configuration documents intended to be used on commands, as a convenience, to supply a slew of additional - * input and configuration (normally more than would be feasible as command arguments). See the "IProfile" interface - * for a detailed description of profiles, their use case, and examples. - * - * The abstract manager is implemented by (at least as part of Imperative) the BasicProfileManager. The BasicProfileManager - * implements the save, load, update, etc. methods in, as the name implies, a "basic" way. In general, the abstract - * manager contains all parameter and profile validation code, methods to write/read/etc and the Basic Manager uses - * most of the internal methods to perform the "work". The basic manager does in some cases change the default abstract - * behavior (such as for loadAll profile and loadDependencies). - * - * Imperative, however, uses the the "Cli Profile Manager", which extends the "Basic Profile Manager". The CLI Manager includes - * additional capabilities, such as creating or updating a profile from command line arguments. - * - * In general, Imperative CLI's will use the "Cli Profile Manager", where the "Basic Profile Manager" is normally sufficient - * for usage outside of Imperative (for usage in building extensions to editors, Electron apps, programmatic usage of - * APIs built by implementations of Imperative, etc.), although either can be used. - * - * It is not an absolute requirement, but in the case of an Imperative CLI, the "Basic Profile Manager initialize()" API - * is invoked to create the required directories and sub-directories. This is NOT a requirement, but avoiding "initialize()" - * means you must supply all configuration information to the manager when creating an instance. See the "initialize()" API - * method in the "BasicProfileManager" for full details. - * - * @export - * @abstract - * @class AbstractProfileManager - */ -export abstract class AbstractProfileManager { - /** - * The default profile file extension (YAML format) - all profiles are stored in YAML format including - * the meta profile file. - * @static - * @type {string} - * @memberof ProfileManager - */ - public static readonly PROFILE_EXTENSION: string = ".yaml"; - - /** - * The meta file suffix - always appended to the meta file to distinguish from other profiles. Users then cannot - * supply a profile name that would conflict with the meta file. - * @static - * @type {string} - * @memberof AbstractProfileManager - */ - public static readonly META_FILE_SUFFIX: string = "_meta"; - - /** - * Load counter for this instance of the imperative profile manager. The load counter ensures that we are not - * attempting to load circular dependencies by checking if a load (with dependencies) is attempting a load of - * the same profile twice. The counts are reset when the loads complete, so state should be preserved correctly. - * @private - * @static - * @type {Map} - * @memberof AbstractProfileManager - */ - private mLoadCounter: Map = new Map(); - - /** - * Parameters passed on the constructor (normally used to create additional instances of profile manager objects) - * @private - * @type {IProfileManager} - * @memberof AbstractProfileManager - */ - private mConstructorParms: IProfileManager; - - /** - * The profile root directory is normally supplied on an Imperative configuration document, but it is the - * location where all profile type directories are stored. - * @private - * @type {string} - * @memberof AbstractProfileManager - */ - private mProfileRootDirectory: string; - - /** - * The full set of profile type configurations. The manager needs to ensure that A) the profile type configuration - * is among the set (because it contains schema and dependency specifications) and B) That other type configurations - * are available to verify/load dependencies, etc. - * @private - * @type {T[]} - * @memberof AbstractProfileManager - */ - private mProfileTypeConfigurations: T[]; - - /** - * The profile "type" for this manager - indicating the profile/schema that this manager is working directly with. - * @private - * @type {string} - * @memberof AbstractProfileManager - */ - private mProfileType: string; - - /** - * The profile configuration document for the "type" defined to this manager. Contains the schema and dependency - * specifications for the profile type. - * @private - * @type {T} - * @memberof AbstractProfileManager - */ - private mProfileTypeConfiguration: T; - - /** - * The profile schema for the "type". The JSON schema is used to validate any profiles loaded or saved by this - * profile manager for the type. - * @private - * @type {IProfileSchema} - * @memberof AbstractProfileManager - */ - private mProfileTypeSchema: IProfileSchema; - - /** - * The root directory for the type (contained within the profile root directory). - * @private - * @type {string} - * @memberof AbstractProfileManager - */ - private mProfileTypeRootDirectory: string; - - /** - * The meta file name for this profile type. Of the form "_meta". - * @private - * @type {string} - * @memberof AbstractProfileManager - */ - private mProfileTypeMetaFileName: string; - - /** - * Product display name of the CLI. - * @private - * @type {string} - * @memberof AbstractProfileManager - */ - private mProductDisplayName: string; - - /** - * Logger instance - must be log4js compatible. Can be the Imperative logger (normally), but is required for - * profile manager operation. - * @private - * @type {Logger} - * @memberof AbstractProfileManager - */ - private mLogger: Logger = Logger.getImperativeLogger(); - - /** - * Creates an instance of ProfileManager - Performs basic parameter validation and will create the required - * profile root directory (if it does not exist) and will attempt to load type configurations from the - * existing profile root directory (unless the type definitions are passed on the constructor parameters). - * - * @param {IProfileManager} parms - See the interface for details. - * @memberof ProfileManager - */ - constructor(parms: IProfileManager) { - ImperativeExpect.toNotBeNullOrUndefined(parms, "Profile Manager input parms not supplied."); - ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["type"], - "No profile type supplied on the profile manager parameters."); - ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["profileRootDirectory"], - "No profile root directory supplied on the profile manager parameters"); - if (parms.loadCounter != null) { - this.mLoadCounter = parms.loadCounter; - } - this.mLogger = isNullOrUndefined(parms.logger) ? this.mLogger : parms.logger; - this.mProfileType = parms.type; - this.mProfileRootDirectory = parms.profileRootDirectory; - this.mProfileTypeConfigurations = parms.typeConfigurations; - this.mProductDisplayName = parms.productDisplayName; - if (isNullOrUndefined(this.profileTypeConfigurations) || this.profileTypeConfigurations.length === 0) { - try { - this.mProfileTypeConfigurations = this.collectAllConfigurations(); - if (this.mProfileTypeConfigurations.length === 0) { - throw new ImperativeError({ - msg: `No profile configurations found. ` + - `Please initialize the profile manager OR supply the configurations to the profile manager.` - }); - } - } catch (e) { - throw new ImperativeError({ - msg: `An error occurred collecting all configurations ` + - `from the profile root directory "${this.profileRootDirectory}". ` + - `Please supply the configurations on the profile manager constructor parameters ` + - `OR initialize the profile manager environment. Details: ${e.message}`, - additionalDetails: e - }); - } - } - this.mConstructorParms = parms; - this.mProfileTypeConfiguration = ImperativeExpect.arrayToContain(this.mProfileTypeConfigurations, (entry) => { - return entry.type === this.mProfileType; - }, `Could not locate the profile type configuration for "${this.profileType}" within the input configuration list passed.` + - `\n${inspect(this.profileTypeConfigurations, {depth: null})}`); - for (const config of this.profileTypeConfigurations) { - this.validateConfigurationDocument(config); - } - this.mProfileTypeSchema = this.mProfileTypeConfiguration.schema; - this.mProfileTypeRootDirectory = this.profileRootDirectory + "/" + this.profileType + "/"; - this.mProfileTypeMetaFileName = this.constructMetaName(); - } - - /** - * Accessor for the load counter (protects against circular loading) - * @readonly - * @protected - * @type {Map} - * @memberof AbstractProfileManager - */ - protected get loadCounter(): Map { - return this.mLoadCounter; - } - - /** - * Accessor for the logger instance - passed on the constructor - * @readonly - * @protected - * @type {Logger} - * @memberof AbstractProfileManager - */ - protected get log(): Logger { - return this.mLogger; - } - - /** - * Accessor the input parameters to the constructor - used sometimes to create other instances of profile managers. - * @readonly - * @protected - * @type {IProfileManager} - * @memberof AbstractProfileManager - */ - protected get managerParameters(): IProfileManager { - return this.mConstructorParms; - } - - /** - * Accessor for the profile type specified on the constructor. - * @readonly - * @protected - * @type {string} - * @memberof AbstractProfileManager - */ - protected get profileType(): string { - return this.mProfileType; - } - - /** - * Accesor for the product display name. - * @readonly - * @protected - * @type {string} - * @memberof AbstractProfileManager - */ - protected get productDisplayName(): string { - return this.mProductDisplayName; - } - - /** - * Accessor for the profile type configuration for this manager. - * @readonly - * @protected - * @type {T} - * @memberof AbstractProfileManager - */ - protected get profileTypeConfiguration(): T { - return this.mProfileTypeConfiguration; - } - - /** - * Accessor for the full set of type configurations - passed on the constructor or obtained from reading - * the profile root directories and meta files. - * @readonly - * @protected - * @type {T[]} - * @memberof AbstractProfileManager - */ - protected get profileTypeConfigurations(): T[] { - return this.mProfileTypeConfigurations; - } - - /** - * Accessor for the schema of this type - JSON schema standard - * @readonly - * @protected - * @type {IProfileSchema} - * @memberof AbstractProfileManager - */ - protected get profileTypeSchema(): IProfileSchema { - return this.mProfileTypeSchema; - } - - /** - * Accessor for the profile type root directory (contained within the profile root directory and named by the type itself) - * @readonly - * @protected - * @type {string} - * @memberof AbstractProfileManager - */ - protected get profileTypeRootDirectory(): string { - return this.mProfileTypeRootDirectory; - } - - /** - * Accessor for the profile meta file name - constructed as "_meta" - * @readonly - * @protected - * @type {string} - * @memberof AbstractProfileManager - */ - protected get profileTypeMetaFileName(): string { - return this.mProfileTypeMetaFileName; - } - - /** - * Accessor for the profile root directory - supplied on the constructor - used to construct the profile type - * directory. - * @readonly - * @protected - * @type {string} - * @memberof AbstractProfileManager - */ - protected get profileRootDirectory(): string { - return this.mProfileRootDirectory; - } - - /** - * Obtains all profile names for the profile "type" specified on the manager. The names are obtained from the - * filesystem (in the profile type directory) and the meta file is NOT returned in the list. - * @returns {string[]} - The list of profile names (obtained from disk). - * @memberof AbstractProfileManager - */ - public getAllProfileNames(): string[] { - return ProfileIO.getAllProfileNames(this.profileTypeRootDirectory, - AbstractProfileManager.PROFILE_EXTENSION, this.constructMetaName()); - } - - /** - * Accessor that returns a copy of of the profile configuration document. - * @readonly - * @type {IProfileTypeConfiguration[]} - * @memberof AbstractProfileManager - */ - public get configurations(): IProfileTypeConfiguration[] { - return JSON.parse(JSON.stringify(isNullOrUndefined(this.profileTypeConfigurations) ? [] : this.profileTypeConfigurations)); - } - - /** - * Save a profile to disk. Ensures that the profile specified is valid (basic and schema validation) and invokes the implementations - * "saveProfile" method to perform the save and formulate the response. - * @template S - * @param {ISaveProfile} parms - See interface for details - * @returns {Promise} - The promise that is fulfilled with the response object (see interface for details) or rejected - * with an Imperative Error. - * @memberof AbstractProfileManager - */ - public async save(parms: S): Promise { - // Validate the input parameters - ImperativeExpect.toNotBeNullOrUndefined(parms, - `A request was made to save a profile of type "${this.profileType}", but no parameters were supplied.`); - ImperativeExpect.keysToBeDefined(parms, ["profile"], - `A request was made to save a profile of type "${this.profileType}", but no profile was supplied.`); - ImperativeExpect.keysToBeDefined(parms, ["name"], - `A request was made to save a profile of type "${this.profileType}", but no name was supplied.`); - - // Ensure that the type is filled in - a mismatch will be thrown if the type indicates a type other than the manager's current type - parms.type = parms.type || this.profileType; - - // Log the invocation - this.log.info(`Saving profile "${parms.name}" of type "${this.profileType}"...`); - - // Perform basic profile object validation (not specific to create - just that the object is correct for our usage here) - this.log.debug(`Validating the profile ("${parms.name}" of type "${this.profileType}") before save.`); - await this.validate({ - name: parms.name, - profile: parms.profile - }); - - // Protect against overwriting the profile - unless explicitly requested - this.protectAgainstOverwrite(parms.name, parms.overwrite || false); - - // Invoke the implementation - this.log.trace(`Invoking save profile of implementation...`); - const response = await this.saveProfile(parms); - if (isNullOrUndefined(response)) { - throw new ImperativeError({msg: `The profile manager implementation did NOT return a profile save response.`}, - {tag: `Internal Profile Management Error`}); - } - - // If the meta file exists - read to ensure that the name of the default is not null or undefined - this can - // happen after the profile environment is initialized for the first time. - if (this.locateExistingProfile(this.constructMetaName())) { - const meta = this.readMeta(this.constructFullProfilePath(this.constructMetaName())); - if (isNullOrUndefined(meta.defaultProfile)) { - this.log.debug(`Setting "${parms.name}" of type "${parms.type}" as the default profile.`); - this.setDefault(parms.name); - } - } else if (parms.updateDefault || isNullOrUndefined(this.locateExistingProfile(this.constructMetaName()))) { - this.log.debug(`Setting "${parms.name}" of type "${parms.type}" as the default profile.`); - this.setDefault(parms.name); - } - - // Return the save/create response to the caller - this.log.info(`Save API complete for profile "${parms.name}" of type "${this.profileType}".`); - return response; - } - - /** - * Load a profile from disk. Ensures that the parameters are valid and loads the profile specified by name OR the default profile if - * requested. If load default is requested, any name supplied is ignored. - * @template L - * @param {ILoadProfile} parms - See the interface for details. - * @returns {Promise} - The promise that is fulfilled with the response object (see interface for details) or rejected - * with an Imperative Error. - * @memberof AbstractProfileManager - */ - public async load(parms: L): Promise { - // Ensure the correct parameters were supplied - ImperativeExpect.toNotBeNullOrUndefined(parms, `Profile load requested for type "${this.profileType}", but no parameters supplied.`); - - // Set defaults if not present - parms.loadDefault = (parms.loadDefault == null) ? false : parms.loadDefault; - parms.failNotFound = (parms.failNotFound == null) ? true : parms.failNotFound; - parms.loadDependencies = (parms.loadDependencies == null) ? true : parms.loadDependencies; - - // Log the API call - this.log.info(`Loading profile "${parms.name || "default"}" of type "${this.profileType}"...`); - - // If load default is true, avoid the name check - if loading the default, we ignore the name - if (!parms.loadDefault) { - ImperativeExpect.keysToBeDefined(parms, ["name"], `A profile load was requested for type "${this.profileType}", ` + - `but no profile name was specified.`); - } else { - parms.name = this.getDefaultProfileName(); - this.log.debug(`The default profile for type "${this.profileType}" is "${parms.name}".`); - - // If we don't find the default name and we know fail not found is false, then return here - if (parms.name == null) { - if (!parms.failNotFound) { - return this.failNotFoundDefaultResponse("default was requested"); - } else { - this.log.error(`No default profile exists for type "${this.profileType}".`); - throw new ImperativeError({msg: `No default profile set for type "${this.profileType}".`}); - } - } else if (!this.locateExistingProfile(parms.name)) { - this.log.error(`Default profile "${parms.name}" does not exist for type "${this.profileType}".`); - throw new ImperativeError({ - msg: `Your default profile named ${parms.name} does not exist for type ${this.profileType}.\n` + - `To change your default profile, run "${ImperativeConfig.instance.rootCommandName} profiles set-default ` + - `${this.profileType} ".` - }); - } - } - - // Attempt to protect against circular dependencies - if the load count increases to 2 for the same type/name - // Then some profile in the chain attempted to re-load this profile. - const mapKey: string = ProfileUtils.getProfileMapKey(this.profileType, parms.name); - let count = this.loadCounter.get(mapKey); - if (count == null) { - count = 1; - } else { - count++; - } - this.loadCounter.set(mapKey, count); - this.log.debug(`Load count for "type_name" key "${mapKey}" is ${count}`); - if (count >= 2) { - this.log.error(`Circular dependencies detected in profile "${parms.name}" of type "${this.profileType}".`); - throw new ImperativeError({ - msg: `A circular profile dependency was detected. Profile "${parms.name}" of type "${this.profileType}" ` + - `either points directly to itself OR a dependency of this profile points to this profile.` - }); - } - - // Invoke the implementation - let response; - try { - this.log.debug(`Invoking the implementation to load profile "${parms.name}" of type "${this.profileType}".`); - response = await this.loadProfile(parms); - } catch (e) { - this.log.error(`Load implementation error: ${e.message}`); - this.loadCounter.set(mapKey, 0); - throw e; - } - - // Reset the load counter - this.loadCounter.set(mapKey, 0); - - this.log.info(`Load API completed for profile "${parms.name}" of type "${this.profileType}".`); - return response; - } - - /** - * Validate a profile. Includes basic and schema validation. Can be called explicitly, but is also called during - * loads and saves to protect the integrity of the profiles against the type definitions. - * @template V - * @param {IValidateProfile} parms - See the interface for details - * @returns {Promise} - The promise that is fulfilled with the response object (see interface for details) or rejected - * with an Imperative Error. - * @memberof AbstractProfileManager - */ - public async validate(parms: V): Promise { - // Ensure that parms are passed - ImperativeExpect.toNotBeNullOrUndefined(parms, `A request was made to validate a profile ` + - `(of type "${this.profileType}"), but no parameters were specified.`); - - // Ensure defaults are set - parms.strict = (parms.strict == null) ? false : parms.strict; - - // Pass the schema to the implementations validate - const validateParms = JSON.parse(JSON.stringify(parms)); - validateParms.schema = this.profileTypeSchema; - - // Log the API call - this.log.info(`Validating profile of type "${this.profileType}"...`); - - // Validate the profile object is correct for our usage here - does not include schema validation - this.validateProfileObject(parms.name, this.profileType, parms.profile); - - // Invoke the implementation - this.log.trace(`Invoking the profile validation implementation for profile "${parms.name}" of type "${this.profileType}".`); - - const response = await this.validateProfile(validateParms); - if (isNullOrUndefined(response)) { - throw new ImperativeError({msg: `The profile manager implementation did NOT return a profile validate response.`}, - {tag: `Internal Profile Management Error`}); - } - - return response; - } - - /** - * Merge two profiles together. Useful when updating existing profiles with a few new - * fields, for example. - * @param {IProfile} oldProfile - the old profile, fields on this will have lower precedence - * @param {IProfile} newProfile - the new profile, fields on this will have higher precedence - * @returns {IProfile} - the merged profile - */ - public mergeProfiles(oldProfile: IProfile, newProfile: IProfile): IProfile { - const DeepMerge = require("deepmerge"); - // clone both profiles while merging so that the originals are not modified - const mergedProfile = DeepMerge(JSON.parse(JSON.stringify(oldProfile)), JSON.parse(JSON.stringify(newProfile))); - - // there can only be one dependency per type, - // but it's possible that the user only wants to - // update one of the dependencies, and keep dependencies of other types - // so we will allow merging of the dependencies field - // but will double check that no duplicates have been created - if (!isNullOrUndefined(mergedProfile.dependencies) && !isNullOrUndefined(newProfile.dependencies) - && newProfile.dependencies.length > 0) { - const markForDeletionKey = "markedForDelete"; - for (const newDependency of newProfile.dependencies) { - for (const mergedDependency of mergedProfile.dependencies) { - if (mergedDependency.type === newDependency.type && - mergedDependency.name !== newDependency.name) { - this.log.debug("Deleting dependency from old profile which was overridden " + - "by the new dependency of name %s", - newDependency.name); - mergedDependency[markForDeletionKey] = true; - } - } - } - mergedProfile.dependencies = mergedProfile.dependencies.filter((dependency: IProfileDependency) => { - - return !(dependency as any)[markForDeletionKey]; - }); - } - // we like the merging functionality for most things, but - // if we merge array type profile fields, then users will not be able to update array type - // fields through the CLI. So instead we will take array fields from the new type verbatim - // we'll use this helper to search through - const DataObjectParser = require("dataobject-parser"); - const findArrayFields = (property: any, propertyPath: string) => { - if (Array.isArray(property) && !isString(property)) { - const newProfileProperty = new DataObjectParser(newProfile).get(propertyPath); - - // does the array type property appear on the newer profile - if (!isNullOrUndefined(newProfileProperty)) { - // if so, wipe out the merged array with the value from the newer profile - this.log.debug("Replacing array type profile field \"%s\" with new value", propertyPath); - new DataObjectParser(mergedProfile).set(propertyPath, newProfileProperty); - } - } else if (!isString(property)) { - for (const childPropertyName of Object.keys(property)) { - // object.keys returns array indices as well, - // so we won't recursively call our helper if - // the property name is just a number - const propertyNameIsArrayIndex = /^[0-9]+$/.test(childPropertyName); - if (!propertyNameIsArrayIndex) { - const newPropertyPath = propertyPath + "." + childPropertyName; - this.log.debug("Searching for array properties to replace in the field %s", newPropertyPath); - findArrayFields(property[childPropertyName], newPropertyPath); - } - } - } - }; - for (const propertyName of Object.keys(mergedProfile)) { - if (propertyName !== "dependencies") { - findArrayFields(mergedProfile[propertyName], propertyName); - } - } - return mergedProfile; - } - - /** - * Deletes a profile from disk. Ensures that the parameters are correct and removes the profile. If the profile is listed as a dependency of - * other profiles it will NOT delete the profile unless "rejectIfDependency" is set to false. - * @template D - * @param {IDeleteProfile} parms - See the interface for details - * @returns {Promise} - The promise that is fulfilled with the response object (see interface for details) or rejected - * with an Imperative Error. - * @memberof AbstractProfileManager - */ - public async delete(parms: D): Promise { - // Validate that the delete parms are valid - ImperativeExpect.toNotBeNullOrUndefined(parms, - `A delete was requested for profile type "${this.profileType}", but no parameters were specified.`); - ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["name"], - `A delete was requested for profile type "${this.profileType}", but the name specified is undefined or blank.`); - - // Ensure defaults are set - parms.rejectIfDependency = (isNullOrUndefined(parms.rejectIfDependency)) ? true : parms.rejectIfDependency; - - // Log the API call - this.log.info(`Deleting profile "${parms.name}" of type "${this.profileType}"...`); - - // Check if the profile exists before continuing - if (isNullOrUndefined(this.locateExistingProfile(parms.name))) { - const msg: string = `Profile "${parms.name}" of type "${this.profileType}" does not exist.`; - this.log.error(msg); - throw new ImperativeError({msg}); - } - - // If specified, reject the delete if this profile is listed as dependency for another profile (of any type) - if (parms.rejectIfDependency) { - this.log.trace(`Reject if dependency was specified, loading all profiles to check if "${parms.name}" of type ` + - `"${this.profileType}" is a dependency.`); - const allProfiles = await this.loadAll({ noSecure: true }); - this.log.trace(`All profiles loaded (for dependency check).`); - const flatten = ProfileUtils.flattenDependencies(allProfiles); - const dependents: IProfile[] = this.isDependencyOf(flatten, parms.name); - if (dependents.length > 0) { - let depList: string = ""; - for (const dep of dependents) { - depList += ("\n" + `Name: "${dep.name}" Type: "${dep.type}"`); - } - const msg: string = `The profile specified for deletion ("${parms.name}" of type ` + - `"${this.profileType}") is marked as a dependency for profiles:` + depList; - throw new ImperativeError({msg}); - } - } - - this.log.trace(`Invoking implementation to delete profile "${parms.name}" of type "${this.profileType}".`); - const response = await this.deleteProfile(parms); - if (isNullOrUndefined(response)) { - throw new ImperativeError({msg: `The profile manager implementation did NOT return a profile delete response.`}, - {tag: `Internal Profile Management Error`}); - } - - // If the meta file exists - read to check if the name of the default profile is the same as - // the profile that was deleted. If so, reset it to null. - if (this.locateExistingProfile(this.constructMetaName())) { - const meta = this.readMeta(this.constructFullProfilePath(this.constructMetaName())); - if (meta.defaultProfile === parms.name) { - this.log.debug(`Profile deleted was the default. Clearing the default profile for type "${this.profileType}".`); - this.clearDefault(); - response.defaultCleared = true; - } - } - - return response; - } - - /** - * Update the profile - The action performed is dictacted by the implementation of the Abstract manager. - * @template U - * @param {IUpdateProfile} parms - See the interface for details - * @returns {Promise} - The promise that is fulfilled with the response object (see interface for details) or rejected - * with an Imperative Error. - * @memberof AbstractProfileManager - */ - public async update(parms: U): Promise { - // Validate the input parameters are correct - ImperativeExpect.toNotBeNullOrUndefined(parms, - `An update for a profile of type "${this.profileType}" was requested, but no parameters were specified.`); - ImperativeExpect.keysToBeDefinedAndNonBlank(parms, ["name"], - `An update for a profile of type "${this.profileType}" was requested, but no name was specified.`); - - // Log the API call - this.log.info(`Updating profile "${parms.name}" of type "${this.profileType}"...`); - - // Invoke the implementation - this.log.trace(`Invoking update profile implementation for profile "${parms.name}" of type "${this.profileType}".`); - const response = await this.updateProfile(parms); - if (isNullOrUndefined(response)) { - throw new ImperativeError({msg: `The profile manager implementation did NOT return a profile update response.`}, - {tag: `Internal Profile Management Error`}); - } - - return response; - } - - /** - * Sets the default profile for the profile managers type. - * @param {string} name - The name of the new default - * @returns {string} - The response string (or an error is thrown if the request cannot be completed); - * @memberof AbstractProfileManager - */ - public setDefault(name: string): string { - // Log the API call - this.log.info(`Set default API invoked. Setting "${name}" as default for type "${this.profileType}".`); - - // Construct the path to the profile that we are to set as the default for this type - const profileLocation: string = this.locateExistingProfile(name); - - // Find the meta profile - it may NOT exists - this is OK - will be created - let metaFilePath: string = this.locateExistingProfile(this.constructMetaName()); - - // Read the meta profile OR construct a new profile if it does NOT exist - let meta: IMetaProfile; - if (profileLocation) { - if (metaFilePath) { - this.log.trace(`The meta file exists for type "${this.profileType}". Reading meta...`); - meta = this.readMeta(metaFilePath); - this.log.trace(`Setting default in the meta file for type ${this.profileType}.`); - this.setDefaultInMetaObject(meta, name); - } else { - this.log.info(`The meta file does NOT exist for type "${this.profileType}", ` + - `writing the meta file and default profile ("${name}")`); - metaFilePath = this.constructFullProfilePath(this.constructMetaName()); - meta = { - defaultProfile: name, - configuration: this.profileTypeConfiguration - }; - } - - // Write the meta file to disk - this.log.info(`Writing the updated meta file to disk. Default: ${meta.defaultProfile}`); - ProfileIO.writeMetaFile(meta, metaFilePath); - } else { - const msg: string = `Cannot update default profile for type "${this.profileType}". ` + - `The profile name specified ("${name}") does not exist. ` + - `Please create before attempting to set the default.`; - this.log.error(msg); - // The profile name specified does NOT actually exist. This is an error. - throw new ImperativeError({msg}); - } - - return `Default profile for type "${this.profileType}" set to "${name}".`; - } - - /** - * Clears the default profile for the profile managers type. - * @returns {string} - The response string (or an error is thrown if the request cannot be completed); - * @memberof AbstractProfileManager - */ - public clearDefault(): string { - // Log the API call - this.log.info(`Clear default API invoked for type "${this.profileType}".`); - - // Find the meta profile - it may NOT exists - this is OK - will be created - let metaFilePath: string = this.locateExistingProfile(this.constructMetaName()); - - // Read the meta profile OR construct a new profile if it does NOT exist - let meta: IMetaProfile; - if (metaFilePath) { - this.log.trace(`The meta file exists for type "${this.profileType}". Reading meta...`); - meta = this.readMeta(metaFilePath); - this.log.trace(`Clearing default in the meta file for type ${this.profileType}.`); - this.setDefaultInMetaObject(meta, null); - } else { - this.log.info(`The meta file does NOT exist for type "${this.profileType}", ` + - `writing the meta file without a default profile`); - metaFilePath = this.constructFullProfilePath(this.constructMetaName()); - meta = { - defaultProfile: null, - configuration: this.profileTypeConfiguration - }; - } - - // Write the meta file to disk - this.log.info(`Writing the updated meta file to disk. Default: ${meta.defaultProfile}`); - ProfileIO.writeMetaFile(meta, metaFilePath); - - return `Default profile for type "${this.profileType}" cleared.`; - } - - /** - * Returns the default profile name for this "type" or "undefined" if no default is set. - * @returns {string} - The default profile name or undefined. - * @memberof AbstractProfileManager - */ - public getDefaultProfileName(): string { - const metaFile: string = this.locateExistingProfile(this.constructMetaName()); - let defaultName: string; - if (isNullOrUndefined(metaFile)) { - return undefined; - } - - let meta: IMetaProfile; - try { - meta = this.readMeta(metaFile); - defaultName = meta.defaultProfile; - } catch (err) { - throw new ImperativeError({ - msg: `Error reading "${this.profileType}" meta file: ${err.message}.`, - additionalDetails: err - }); - } - - return defaultName; - } - - /** - * Load all profiles - the behavior is dictated by the implementation. - * @abstract - * @param {ILoadAllProfiles} [parms] - the load parameters - See interface for details - * @returns {Promise} - The list of profiles when the promise is fulfilled or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - public abstract loadAll(parms?: ILoadAllProfiles): Promise; - - /** - * Save profile - performs the profile save according to the implementation - invoked when all parameters are valid - * (according the abstract manager). - * @protected - * @abstract - * @param {ISaveProfile} parms - See interface for details - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract saveProfile(parms: ISaveProfile): Promise; - - /** - * Save profile - performs the profile load according to the implementation - invoked when all parameters are valid - * (according the abstract manager). - * @protected - * @abstract - * @param {ILoadProfile} parms - See interface for details - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract loadProfile(parms: ILoadProfile): Promise; - - /** - * Delete profile - performs the profile delete according to the implementation - invoked when all parameters are valid - * (according the abstract manager). - * @protected - * @abstract - * @param {IDeleteProfile} parms - See interface for details - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract deleteProfile(parms: IDeleteProfile): Promise; - - /** - * Validate profile - performs the profile validation according to the implementation - invoked when all parameters are valid - * (according the abstract manager). - * @protected - * @abstract - * @param {IValidateProfileWithSchema} parms - See interface for details - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract validateProfile(parms: IValidateProfileWithSchema): Promise; - - /** - * Update profile - performs the profile update according to the implementation - invoked when all parameters are valid - * (according the abstract manager). - * @protected - * @abstract - * @param {IUpdateProfile} parms - See interface for details - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract updateProfile(parms: IUpdateProfile): Promise; - - /** - * Load a profiles dependencies - dictacted by the implementation. - * @protected - * @abstract - * @param {string} name - the name of the profile to load dependencies for - * @param {IProfile} profile - The profile to load dependencies for. - * @param {boolean} failNotFound - True to fail "not found" errors - * @returns {Promise} - The promise fulfilled with response or rejected with an ImperativeError. - * @memberof AbstractProfileManager - */ - protected abstract loadDependencies(name: string, profile: IProfile, failNotFound: boolean): Promise; - - /** - * Invokes the profile IO method to delete the profile from disk. - * @protected - * @param {string} name - The name of the profile to delete. - * @returns {string} - The path where the profile was. - * @memberof AbstractProfileManager - */ - protected deleteProfileFromDisk(name: string): string { - const profileFullPath: string = this.locateExistingProfile(name); - ProfileIO.deleteProfile(name, profileFullPath); - return profileFullPath; - } - - /** - * Performs basic validation of a profile object - ensures that all fields are present (if required). - * @protected - * @param name - the name of the profile to validate - * @param type - the type of profile to validate - * @param {IProfile} profile - The profile to validate. - * @memberof AbstractProfileManager - */ - protected validateProfileObject(name: string, type: string, profile: IProfile) { - // Throw an error on type mismatch - if the profile manager type does not match the input profile - ImperativeExpect.toBeEqual(type, this.profileType, - `The profile passed on the create indicates a type ("${type}") that differs from ` + - `the type specified on this instance of the profile manager ("${this.profileType}").`); - - // Ensure that the profile name is specified and non-blank - ImperativeExpect.toBeDefinedAndNonBlank(name, "name", - `The profile passed does not contain a name (type: "${this.profileType}") OR the name property specified is ` + - `not of type "string".`); - - // Ensure that the profile name passed does NOT match the meta profile name - ImperativeExpect.toNotBeEqual(name, this.profileTypeMetaFileName, - `You cannot specify "${name}" as a profile name. ` + - `This profile name is reserved for internal Imperative usage.`); - - - // Validate the dependencies specification - if (!isNullOrUndefined(profile.dependencies)) { - ImperativeExpect.keysToBeAnArray(profile, false, ["dependencies"], `The profile passed ` + - `(name "${name}" of type "${type}") has dependencies as a property, ` + - `but it is NOT an array (ill-formed)`); - - for (const dep of profile.dependencies) { - - // check for name on the dependency - ImperativeExpect.keysToBeDefinedAndNonBlank(dep, ["name"], `The profile passed ` + - `(name "${name}" of type "${type}") has dependencies as a property, ` + - `but an entry does not contain "name".`); - - // check for name on the dependency - ImperativeExpect.keysToBeDefinedAndNonBlank(dep, ["type"], `The profile passed ` + - `(name "${name}" of type "${type}") has dependencies as a property, ` + - `but an entry does not contain "type".`); - } - } - } - - /** - * Validates the profile against the schema for its type and reports and errors located. - * @protected - * @param name - the name of the profile to validate - * @param {IProfile} profile - The profile to validate. - * @param {boolean} [strict=false] - Set to true to enable the "ban unknown properties" specification of the JSON schema spec. In other words, - * prevents profiles with "unknown" or "not defined" proeprties according to the schema document. - * @memberof AbstractProfileManager - */ - protected validateProfileAgainstSchema(name: string, profile: IProfile, strict = false) { - - - // Instance of the validator - const validator = new SchemaValidator(); - - // don't make the user specify this internal field of "dependencies" - // they specify the dependencies on their profile config object, - // and the profile manager will construct them there - const schemaWithDependencies = JSON.parse(JSON.stringify(this.profileTypeSchema)); // copy the schema without modifying - // const dependencyProperty: IProfileProperty = { - // type: "array", - // items: { - // description: "The dependencies", - // type: "object", - // properties: { - // type: { - // description: "The type of dependent profile.", - // type: "string" - // }, - // name: { - // description: "The name of the dependent profile.", - // type: "string" - // }, - // } - // } - // }; - - // If strict mode is requested, then we will remove name and type (because they are inserted by the manager) and - // set the additional properties flag false, which, according to the JSON schema specification, indicates that - // no unknown properties should be present on the document. - if (strict || (!isNullOrUndefined(schemaWithDependencies.additionalProperties) && schemaWithDependencies.additionalProperties === false)) { - schemaWithDependencies.additionalProperties = false; - } - - // TODO - @ChrisB, is this supposed to be commented out? - // schemaWithDependencies.dependencies = dependencyProperty; - const results = validator.validate(profile, schemaWithDependencies, {verbose: true}); - if (results.errors.length > 0) { - let validationErrorMsg: string = `Errors located in profile "${name}" of type "${this.profileType}":\n`; - for (const validationError of results.errors) { - // make the error messages more human readable - const property = validationError.property.replace("instance.", "") - .replace(/^instance$/, "profile"); - validationErrorMsg += property + " " + validationError.message + "\n"; - } - throw new ImperativeError({msg: validationErrorMsg, additionalDetails: results}); - } - } - - /** - * Constructs the full path to the profile of the managers "type". - * @protected - * @param {string} name - The profile name to construct the path - * @param {any} [type=this.profileType] - The type - normally the type specified in the manager. - * @returns {string} - The full profile directory. - * @memberof AbstractProfileManager - */ - protected constructFullProfilePath(name: string, type = this.profileType): string { - return nodePath.resolve(this.profileRootDirectory + "/" + type + "/" + name + AbstractProfileManager.PROFILE_EXTENSION); - } - - /** - * Locate the existing profile for the name specified. - * @protected - * @param {string} name - The profile to locate - * @returns {string} - The fully qualified path or undefined if not found. - * @memberof AbstractProfileManager - */ - protected locateExistingProfile(name: string): string { - const path: string = this.constructFullProfilePath(name); - return ProfileIO.exists(path); - } - - /** - * Standard load failed error message and Imperative Error. - * @protected - * @param {string} name - The name of the profile for which the load failed. - * @memberof AbstractProfileManager - */ - protected loadFailed(name: string) { - throw new ImperativeError({ - msg: `Profile "${name}" of type "${this.profileType}" does not exist.` - }); - } - - /** - * Checks if the profile object passed is "empty" - meaning it has no contents other than that type or name. - * A profile can only specify "dependencies", in the event that it is just acting as a "pointer" to another profile. - * @protected - * @param {IProfile} profile - The profile to check for "emptiness". - * @returns {boolean} True if the profile object is empty. - * @memberof AbstractProfileManager - */ - protected isProfileEmpty(profile: IProfile): boolean { - for (const key in profile) { - if (key === "type" || key === "name") { - continue; - } - if (Object.prototype.hasOwnProperty.call(profile, key)) { - return false; - } - } - return true; - } - - /** - * Loads a specific profile (by name). - * @protected - * @param {string} name - The name of the profile to load. - * @param {boolean} [failNotFound=true] - Specify false to ignore "not found" errors. - * @param {boolean} [loadDependencies=true] - Specify false to NOT load dependencies. - * @returns {Promise} - The promise to fulfill with the response OR reject with an ImperativeError - * @memberof AbstractProfileManager - */ - protected async loadSpecificProfile(name: string, failNotFound: boolean = true, loadDependencies: boolean = true): Promise { - // Ensure that the profile actually exists - const profileFilePath: string = this.locateExistingProfile(name); - - // If it doesn't exist and fail not found is false - if (isNullOrUndefined(profileFilePath) && !failNotFound) { - return this.failNotFoundDefaultResponse(name); - } - - // Throw an error indicating that the load failed - if (isNullOrUndefined(profileFilePath)) { - this.loadFailed(name); - } - - // Load the profile from disk - const profileContents = ProfileIO.readProfileFile(profileFilePath, this.profileType); - - // Insert the name and type - not persisted on disk - - try { - await this.validate({name, profile: profileContents}); - } catch (e) { - throw new ImperativeError({ - msg: `Profile validation error during load of profile "${name}" ` + - `of type "${this.profileType}". Error Details: ${e.message}`, - additionalDetails: e - }); - } - - // Construct the load response for this profile. - const loadResponse: IProfileLoaded = { - message: `Profile "${name}" of type "${this.profileType}" loaded successfully.`, - profile: profileContents, - type: this.profileType, - name, - failNotFound, - dependenciesLoaded: false, - dependencyLoadResponses: [] - }; - - // If requested, load the profile's dependencies - if (loadDependencies) { - const loadDependenciesResponse = await this.loadDependencies(name, profileContents, failNotFound); - if (!isNullOrUndefined(loadDependenciesResponse) && loadDependenciesResponse.length > 0) { - loadResponse.dependenciesLoaded = true; - loadResponse.dependencyLoadResponses = loadDependenciesResponse; - } - } - - // Return the profile and dependencies to caller - return loadResponse; - } - - /** - * Validates a profiles contents against the required dependencies specified on the profile configuration type document. If the document - * indicates that a dependency is required and that dependency is missing from the input profile, an error is thrown. - * @private - * @param {IProfile} profile - The profile to validate dependency specs - * @memberof AbstractProfileManager - */ - protected validateRequiredDependenciesAreSpecified(profile: IProfile) { - if (!isNullOrUndefined(this.profileTypeConfiguration.dependencies) && this.profileTypeConfiguration.dependencies.length > 0) { - const specifiedDependencies = profile.dependencies || []; - for (const dependencyConfig of this.profileTypeConfiguration.dependencies) { - // are required dependencies present in the profile? - if (dependencyConfig.required) { - let requiredDependencyFound = false; - for (const specifiedDependency of specifiedDependencies) { - if (specifiedDependency.type === dependencyConfig.type) { - requiredDependencyFound = true; - } - } - if (!requiredDependencyFound) { - throw new ImperativeError({ - msg: `Profile type "${this.profileType}" specifies a required dependency of type "${dependencyConfig.type}" ` + - `on the "${this.profileType}" profile type configuration document. A dependency of type "${dependencyConfig.type}" ` + - `was NOT listed on the input profile.` - }); - } - } - } - } - } - - - /** - * Checks if the profile (by name) is listed as a dependency of any other profile passed. The type of the profiled named is - * the type of the current manager object. - * @private - * @param {IProfileLoaded[]} profilesToSearch - The list of profiles to search for the dependency. - * @param {string} name - * @returns {IProfile[]} - * @memberof AbstractProfileManager - */ - private isDependencyOf(profilesToSearch: IProfileLoaded[], name: string): IProfile[] { - const foundAsDependencyIn: IProfile[] = []; - for (const prof of profilesToSearch) { - if (!isNullOrUndefined(prof.profile.dependencies)) { - for (const dep of prof.profile.dependencies) { - if (name === dep.name && this.profileType === dep.type) { - foundAsDependencyIn.push(prof); - } - } - } - } - return foundAsDependencyIn; - } - - /** - * Protects a against an overwrite on a profile save (if requested). - * @private - * @param {string} name - The name of the profile to check for existance. - * @param {boolean} overwrite - False to protect against overwrite. - * @memberof AbstractProfileManager - */ - private protectAgainstOverwrite(name: string, overwrite: boolean) { - const file: string = this.locateExistingProfile(name); - if (!isNullOrUndefined(file)) { - if (!overwrite) { - const errMsg: string = `Profile "${name}" of type "${this.profileType}" already ` + - `exists and overwrite was NOT specified.`; - throw new ImperativeError({ - msg: errMsg, - }); - } - } - } - - /** - * Builds the meta profile name for this type. Normally of the form "_meta". This method does NOT include the extension - * @private - * @param {any} [type=this.profileType] - The profile type - defaults to this manager's type. - * @returns {string} - * @memberof AbstractProfileManager - */ - private constructMetaName(type = this.profileType): string { - return type + AbstractProfileManager.META_FILE_SUFFIX; - } - - /** - * Set the default profile name in the meta profile for this type. - * @private - * @param {IMetaProfile} meta - The meta profile contents. - * @param {string} defaultProfileName - The name to set as default. - * @memberof AbstractProfileManager - */ - private setDefaultInMetaObject(meta: IMetaProfile, defaultProfileName: string) { - meta.defaultProfile = defaultProfileName; - } - - /** - * Construct the default response for the situation when a profile is not found (on a load/save/update/etc), but ignore not found is true. - * @private - * @param {string} name - The name of the profile that was not found - * @returns {IProfileLoaded} - The default response. - * @memberof AbstractProfileManager - */ - private failNotFoundDefaultResponse(name: string): IProfileLoaded { - this.log.debug(`Profile "${name}" of type "${this.profileType}" was not found, but failNotFound=False`); - return { - message: `Profile "${name}" of type "${this.profileType}" was not found, but the request indicated to ignore "not found" errors. ` + - `The profile returned is undefined.`, - type: this.profileType, - name, - failNotFound: false, - dependenciesLoaded: false, - dependencyLoadResponses: [] - }; - } - - /** - * Reads all configuration documents from the meta and collects all type configuration documents. - * @private - * @returns {T[]} - * @memberof AbstractProfileManager - */ - private collectAllConfigurations(): T[] { - const configs: T[] = []; - const types: string[] = ProfileIO.getAllProfileDirectories(this.profileRootDirectory); - for (const type of types) { - const meta = this.readMeta(this.constructFullProfilePath(this.constructMetaName(type), type)); - configs.push(meta.configuration); - } - return configs; - } - - /** - * Validate that the schema document passed is well formed for the profile manager usage. Ensures that the - * schema is not overloading reserved properties. - * @private - * @param {IProfileSchema} schema - The schema document to validate. - * @param type - the type of profile for the schema - defaults to the current type for this manager - * @memberof AbstractProfileManager - */ - private validateSchema(schema: IProfileSchema, type = this.profileType) { - ImperativeExpect.keysToBeDefined(schema, ["properties"], `The schema document supplied for the profile type ` + - `("${type}") does NOT contain properties.`); - ImperativeExpect.keysToBeUndefined(schema, ["properties.dependencies"], `The schema "properties" property ` + - `(on configuration document for type "${type}") contains "dependencies". ` + - `"dependencies" is must be supplied as part of the "type" configuration document (no need to formulate the dependencies ` + - `schema yourself).`); - } - - /** - * Validates the basic configuration document to ensure it contains all the proper fields - * @private - * @param {T} typeConfiguration - The type configuration document - * @memberof AbstractProfileManager - */ - private validateConfigurationDocument(typeConfiguration: T) { - ImperativeExpect.keysToBeDefinedAndNonBlank(typeConfiguration, ["type"], `The profile type configuration document for ` + - `"${typeConfiguration.type}" does NOT contain a type.`); - ImperativeExpect.keysToBeDefined(typeConfiguration, ["schema"], `The profile type configuration document for ` + - `"${typeConfiguration.type}" does NOT contain a schema.`); - this.validateSchema(typeConfiguration.schema, typeConfiguration.type); - if (!isNullOrUndefined(typeConfiguration.dependencies)) { - ImperativeExpect.toBeAnArray(typeConfiguration.dependencies, - `The profile type configuration for "${typeConfiguration.type}" contains a "dependencies" property, ` + - `but it is not an array (ill-formed)`); - for (const dep of typeConfiguration.dependencies) { - ImperativeExpect.keysToBeDefinedAndNonBlank(dep, ["type"], "A dependency specified for the " + - "profile definitions did not contain a type."); - } - } - } - - /** - * Validate that a meta profile (one read from disk in particular) is valid. - * @private - * @param {IMetaProfile} meta - The meta profile to validate - * @param {string} [type=this.profileType] - The profile type of this meta file. - * @memberof AbstractProfileManager - */ - private validateMetaProfile(meta: IMetaProfile, type = this.profileType) { - ImperativeExpect.keysToBeDefined(meta, ["configuration"], `A meta profile of type "${type}", does NOT supply a configuration.`); - // ImperativeExpect.keysToBeDefined(meta, ["defaultProfile"], `A meta profile of type "${type}", does NOT supply a default profile.`); - } - - /** - * Read the meta profile and validate the contents. - * @private - * @param {string} path - path to the meta profile - * @param {string} [type=this.profileType] - The profile type - * @returns {IMetaProfile} - The meta profile read from disk. - * @memberof AbstractProfileManager - */ - private readMeta(path: string, type = this.profileType): IMetaProfile { - const meta = ProfileIO.readMetaFile(path); - this.validateMetaProfile(meta); - return meta; - } -} diff --git a/packages/imperative/src/profiles/src/abstract/AbstractProfileManagerFactory.ts b/packages/imperative/src/profiles/src/abstract/AbstractProfileManagerFactory.ts deleted file mode 100644 index 9d910391ae..0000000000 --- a/packages/imperative/src/profiles/src/abstract/AbstractProfileManagerFactory.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { AbstractProfileManager } from "./AbstractProfileManager"; -import { IProfileTypeConfiguration } from "../doc/config/IProfileTypeConfiguration"; -import { IProfileManagerFactory } from "../doc/api/IProfileManagerFactory"; -/** - * Abstract profile manager (implemented by imperative, etc.) - * @export - * @abstract - * @class AbstractProfileManagerFactory - * @implements {IProfileManagerFactory} - * @template T - */ -export abstract class AbstractProfileManagerFactory implements IProfileManagerFactory { - /** - * Returns and instance of the profile manager for the type specified. - * @abstract - * @param {string} type - the profile type - * @returns {AbstractProfileManager} - The manager - * @memberof AbstractProfileManagerFactory - */ - public abstract getManager(type: string): AbstractProfileManager; -} diff --git a/packages/imperative/src/profiles/src/constants/ProfilesConstants.ts b/packages/imperative/src/profiles/src/constants/ProfilesConstants.ts index fb035cf294..88c15f84b1 100644 --- a/packages/imperative/src/profiles/src/constants/ProfilesConstants.ts +++ b/packages/imperative/src/profiles/src/constants/ProfilesConstants.ts @@ -13,10 +13,5 @@ * Constants used within the auto-generated profiles group */ export class ProfilesConstants { - public static readonly PROFILES_COMMAND_TYPE_KEY = "profileTypeIdentifier"; public static readonly PROFILES_OPTION_SECURELY_STORED = "managed by"; - public static readonly DEPRECATE_TO_CONFIG_INIT = "The 'config init' command"; - public static readonly DEPRECATE_TO_CONFIG_LIST = "The 'config list' command"; - public static readonly DEPRECATE_TO_CONFIG_EDIT = "Edit your Zowe V2 configuration"; - public static readonly DEPRECATE_TO_CONFIG_SET = "The 'config set' command"; } diff --git a/packages/imperative/src/profiles/src/doc/api/IProfileManagerFactory.ts b/packages/imperative/src/profiles/src/doc/api/IProfileManagerFactory.ts deleted file mode 100644 index cb13380dbb..0000000000 --- a/packages/imperative/src/profiles/src/doc/api/IProfileManagerFactory.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfileTypeConfiguration } from "../config/IProfileTypeConfiguration"; -import { AbstractProfileManager } from "../../abstract/AbstractProfileManager"; -/** - * Profile manager factory inteface - implemented by the abstract profile manager in this profiles - * package and created by Imperative and other packages that need to influence the way the profile manager - * is allocated, configured. - * @export - * @interface IProfileManagerFactory - * @template T - */ -export interface IProfileManagerFactory { - /** - * Returns an instance of the profile manager specific to the "type" passed - types are defined by Imeprative - * configuration/init - * @param {string} type - The profile type. - * @returns {AbstractProfileManager} - An instance of the profile manager. - * @memberof IProfileManagerFactory - */ - getManager(type: string): AbstractProfileManager; -} diff --git a/packages/imperative/src/profiles/src/doc/config/IProfileTypeConfiguration.ts b/packages/imperative/src/profiles/src/doc/config/IProfileTypeConfiguration.ts index 0a1bb86c31..af454d6ee4 100644 --- a/packages/imperative/src/profiles/src/doc/config/IProfileTypeConfiguration.ts +++ b/packages/imperative/src/profiles/src/doc/config/IProfileTypeConfiguration.ts @@ -14,9 +14,9 @@ import { IProfileDependency } from "../definition/IProfileDependency"; /** * The profile "type" configuration document. Provides all configuration information for the "type". A profile - * "type" is an arbirarty (implementation defined) category used to isolate configuration documents, provide + * "type" is an arbitrary (implementation defined) category used to isolate configuration documents, provide * ease of configuration for complex CLIs (user only configures what they'll use), and allows the CLI to be - * extendable in an isolated fashion. See the "IProfile" and "BasicProfileManager" for more detailed profile info. + * extendable in an isolated fashion. See the "IProfile" for more detailed profile info. * @export * @interface IProfileTypeConfiguration */ diff --git a/packages/imperative/src/profiles/src/doc/index.ts b/packages/imperative/src/profiles/src/doc/index.ts index 2177e34d5e..2a83e06d9b 100644 --- a/packages/imperative/src/profiles/src/doc/index.ts +++ b/packages/imperative/src/profiles/src/doc/index.ts @@ -9,8 +9,6 @@ * */ -export * from "./api/IProfileManagerFactory"; - export * from "./config/IProfileTypeConfiguration"; export * from "./definition"; diff --git a/packages/imperative/src/profiles/src/doc/parms/IDeleteProfile.ts b/packages/imperative/src/profiles/src/doc/parms/IDeleteProfile.ts deleted file mode 100644 index 90782c6572..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IDeleteProfile.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * Parameters to the profile manager "delete" API. - * @export - * @interface IDeleteProfile - */ -export interface IDeleteProfile { - /** - * The name of the profile to delete - the type is specified by the current manager object. - * @type {string} - * @memberof IDeleteProfile - */ - name: string; - /** - * If true, rejects the deletion of the profile if it is found to be a dependency of another profile. - * @type {boolean} - * @memberof IDeleteProfile - */ - rejectIfDependency?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/ILoadAllProfiles.ts b/packages/imperative/src/profiles/src/doc/parms/ILoadAllProfiles.ts deleted file mode 100644 index 97ca5b014c..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/ILoadAllProfiles.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * Optional parameters to profile manager load all profiles - * @export - * @interface ILoadAllProfiles - */ -export interface ILoadAllProfiles { - /** - * If true, do not load secure fields - * @type {boolean} - * @memberof ILoadAllProfiles - */ - noSecure?: boolean; - /** - * If true, loads only the profiles of the current instance of the profile - * managers "type" - specified when allocating the profile manager. - * @type {boolean} - * @memberof ILoadAllProfiles - */ - typeOnly?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/ILoadProfile.ts b/packages/imperative/src/profiles/src/doc/parms/ILoadProfile.ts deleted file mode 100644 index 36f2db6223..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/ILoadProfile.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * Profile Manager "loadProfile" input parameters. Indicates which profile to load (named or default) and if - * not finding the profile should be considered and error, etc. - * @export - * @interface ILoadProfile - */ -export interface ILoadProfile { - /** - * The name of the profile to load - ignored if "loadDefault" is true - the type is indicated by the - * instance of the instantiated profile manager. - * @type {string} - * @memberof ILoadProfile - */ - name?: string; - /** - * Load the default profile for the "type" specified in the profile manager instance - if specified, "name" is - * ignored. - * @type {boolean} - * @memberof ILoadProfile - */ - loadDefault?: boolean; - /** - * Under "normal" circumstances, attempting to load a non-existant profile is an error, however, you may indicate - * that the profile manager should treat this as a "soft" failure, meaning the promise for the load API will - * be fulfilled - with the appropriate status message and no profile. - * @type {boolean} - * @memberof ILoadProfile - */ - failNotFound?: boolean; - /** - * Profiles can have dependencies. Specify "false" if you want to avoid loading the dependencies of this profile. - * True is the default. - * @type {boolean} - * @memberof ILoadProfile - */ - loadDependencies?: boolean; - /** - * If true, fields that indicate "secure" are not loaded. The properties will still be present in the profiles - * loaded with a value of "securely_stored". - * @type {boolean} - * @memberof ILoadProfile - */ - noSecure?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IProfileManager.ts b/packages/imperative/src/profiles/src/doc/parms/IProfileManager.ts index c4f4ac6cb9..df8e1f695e 100644 --- a/packages/imperative/src/profiles/src/doc/parms/IProfileManager.ts +++ b/packages/imperative/src/profiles/src/doc/parms/IProfileManager.ts @@ -19,16 +19,6 @@ import { Logger } from "../../../../logger"; import { IProfileTypeConfiguration } from "../config/IProfileTypeConfiguration"; export interface IProfileManager { - /** - * The profiles directory (normally obtained from the Imperative config). The profile root directory contains - * a list of type directories, within each will be the profiles of that type and the meta file. The meta file - * for a type contains the default specifications and the profile type configuration document. Use the "initialize" - * API method on the Profile Manager to create the appropriate structure based on your configuration documents. - * - * @type {string} - * @memberof IProfileManager - */ - profileRootDirectory: string; /** * The profile type for this manager - the configuration document for the type can either be supplied on the * "typeConfigurations" property on this object OR the mananger will attempt to extract it from the profile @@ -61,12 +51,6 @@ export interface IProfileManager { */ typeConfigurations?: T[]; - /** - * Map of which profile types have been loaded so far, to avoid circular profile loads - * Used internally by profile manager classes - */ - loadCounter?: Map; - /** * Product display name of CLI * @type {string} diff --git a/packages/imperative/src/profiles/src/doc/parms/ISaveProfile.ts b/packages/imperative/src/profiles/src/doc/parms/ISaveProfile.ts deleted file mode 100644 index 7d6219d55b..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/ISaveProfile.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfile } from "../definition/IProfile"; - -/** - * Parameters to the "save()" profile API. - * - * Note: This profile could contain the following additional arguments, - * which will only be kept in memory (for a short period of time) and NOT saved to a file. - * @type {string} username - The username to be securely saved to this profile. - * @type {string} password - The password for the username to be securely saved to this profile. - * - * @export - * @interface ISaveProfile - */ -export interface ISaveProfile { - /** - * The profile contents - must extend the IProfile interface to function properly with Imperative. The contents - * are always validated against the schema documents (and basic validation occurs) - * - * @type {IProfile} - * @memberof ISaveProfile - */ - profile: IProfile; - - /** - * The name of the profile to save - * - * @type {string} - * @memberof ISaveProfile - */ - name: string; - - /** - * The type of profile to save - * @type {string} - * @memberof ISaveProfile - */ - type: string; - - /** - * Set to true to update the default profile for the profile type. - * @type {boolean} - * @memberof ISaveProfile - */ - updateDefault?: boolean; - /** - * Set to true to overwrite an existing profile of the same name. If false, an error is thrown if the profile - * already exists. - * @type {boolean} - * @memberof ISaveProfile - */ - overwrite?: boolean; - - /** - * The argument to disable populating defaults - * @type {boolean} - * @memberof ISaveProfileFromCliArgs - */ - disableDefaults?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/ISaveProfileFromCliArgs.ts b/packages/imperative/src/profiles/src/doc/parms/ISaveProfileFromCliArgs.ts deleted file mode 100644 index d74ad59f2e..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/ISaveProfileFromCliArgs.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { Arguments } from "yargs"; -import { ISaveProfile } from "./ISaveProfile"; - -/** - * Parameters for creating a profile from command line arguments - normally invoked from a command handler that - * is pre-built by imperative. - * @export - * @interface ICreateProfileFromArgs - */ -export interface ISaveProfileFromCliArgs extends ISaveProfile { - /** - * The Yargs style arguments - supplied from the command invocation. - * @type {Arguments} - * @memberof ISaveProfileFromCliArgs - */ - args?: Arguments; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/ISetDefaultProfile.ts b/packages/imperative/src/profiles/src/doc/parms/ISetDefaultProfile.ts deleted file mode 100644 index dd481c8ee6..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/ISetDefaultProfile.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * Parameters for the setDefault Profile Manager API. - * @export - * @interface ISetDefaultProfile - */ -export interface ISetDefaultProfile { - /** - * The name of the profile to set as the default (the type is indicated by the profile manager object). - * @type {string} - * @memberof ISetDefaultProfile - */ - name: string; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IUpdateProfile.ts b/packages/imperative/src/profiles/src/doc/parms/IUpdateProfile.ts deleted file mode 100644 index 906743a780..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IUpdateProfile.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfile } from "../definition/IProfile"; - -/** - * Parameters to update a profile - The basic implementation simply overwrites the existing profile with the new - * contents specified, unless merge is true, and the contents of the old profile are merged with the contents from - * the update profile. - * - * Note: This profile could contains the following additional arguments, - * which will only be kept in memory (for a short period of time) and NOT saved to a file. - * @type {string} username - The username to be securely saved to this profile. - * @type {string} password - The password for the username to be securely saved to this profile. - * - * @export - * @interface IUpdateProfile - */ -export interface IUpdateProfile { - /** - * The name of the profile to update. - * @type {string} - * @memberof IUpdateProfile - */ - name?: string; - /** - * Should the contents of the new profile be merged with the contents of the old one? - * @type {boolean} - */ - merge?: boolean; - /** - * The contents of the profile for the update - if merge is NOT specified, simply overwrites the existing - * profile with the contents specified here. - * @type {IProfile} - * @memberof IUpdateProfile - */ - profile?: IProfile; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IUpdateProfileFromCliArgs.ts b/packages/imperative/src/profiles/src/doc/parms/IUpdateProfileFromCliArgs.ts deleted file mode 100644 index e10e345d3c..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IUpdateProfileFromCliArgs.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IUpdateProfile } from "./IUpdateProfile"; -import { Arguments } from "yargs"; -/** - * TODO - wasn't this moved??? - * @export - * @interface IUpdateProfileFromCliArgs - * @extends {IUpdateProfile} - */ -export interface IUpdateProfileFromCliArgs extends IUpdateProfile { - args: Arguments; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IValidateProfile.ts b/packages/imperative/src/profiles/src/doc/parms/IValidateProfile.ts deleted file mode 100644 index 4665f09822..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IValidateProfile.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfile } from "../definition/IProfile"; - -/** - * Parameters to the "validate()" profile manager APIs. Validates a profile structure (basic and schema) - * @export - * @interface IValidateProfile - */ -export interface IValidateProfile { - /** - * The name of the profile to validate. - * @type {string} - * @memberof IValidateProfile - */ - name: string; - /** - * The profile contents to validate. - * @type {IProfile} - * @memberof IValidateProfile - */ - profile: IProfile; - /** - * Specify true to indicate the "ban unknown properties" specification of JSON schema. Meaning, any properties - * found on the input profile that are NOT specified on the schema cause the validation to fail. - * @type {boolean} - * @memberof IValidateProfile - */ - strict?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IValidateProfileForCLI.ts b/packages/imperative/src/profiles/src/doc/parms/IValidateProfileForCLI.ts deleted file mode 100644 index 3305d1c332..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IValidateProfileForCLI.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IValidateProfileWithSchema } from "./IValidateProfileWithSchema"; - -/** - * Input to the "validateProfile" internal API. Indicates the schema document to be used for the validation. - * Used with the CLI Profile manager - validation is skipped until the profile is fully built - * @export - * @interface IValidateProfileWithSchema - * @extends {IValidateProfile} - */ -export interface IValidateProfileForCLI extends IValidateProfileWithSchema { - /** - * If false/undefined, validation will be skipped until validation - * is called again with "true" (indicating that the profile building is complete) - */ - readyForValidation: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/IValidateProfileWithSchema.ts b/packages/imperative/src/profiles/src/doc/parms/IValidateProfileWithSchema.ts deleted file mode 100644 index d7c384d6e8..0000000000 --- a/packages/imperative/src/profiles/src/doc/parms/IValidateProfileWithSchema.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfileSchema } from "../definition/IProfileSchema"; -import { IValidateProfile } from "./IValidateProfile"; - -/** - * Input to the "validateProfile" internal API. Indicates the schema document to be used for the validation. - * @export - * @interface IValidateProfileWithSchema - * @extends {IValidateProfile} - */ -export interface IValidateProfileWithSchema extends IValidateProfile { - /** - * The profile JSON schema document. - * @type {IProfileSchema} - * @memberof IValidateProfileWithSchema - */ - schema: IProfileSchema; -} diff --git a/packages/imperative/src/profiles/src/doc/parms/index.ts b/packages/imperative/src/profiles/src/doc/parms/index.ts index 399a3a8538..6831ca13a7 100644 --- a/packages/imperative/src/profiles/src/doc/parms/index.ts +++ b/packages/imperative/src/profiles/src/doc/parms/index.ts @@ -9,15 +9,4 @@ * */ -export * from "./IDeleteProfile"; -export * from "./ILoadAllProfiles"; -export * from "./ILoadProfile"; export * from "./IProfileManager"; -export * from "./ISaveProfile"; -export * from "./ISaveProfileFromCliArgs"; -export * from "./ISetDefaultProfile"; -export * from "./IUpdateProfile"; -export * from "./IUpdateProfileFromCliArgs"; -export * from "./IValidateProfile"; -export * from "./IValidateProfileForCLI"; -export * from "./IValidateProfileWithSchema"; diff --git a/packages/imperative/src/profiles/src/doc/response/IProfileDeleted.ts b/packages/imperative/src/profiles/src/doc/response/IProfileDeleted.ts deleted file mode 100644 index 8edf26611e..0000000000 --- a/packages/imperative/src/profiles/src/doc/response/IProfileDeleted.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * The success response to the profile "delete()" API. - * @export - * @interface IProfileDeleted - */ -export interface IProfileDeleted { - /** - * The path to the profile that was deleted. - * @type {string} - * @memberof IProfileDeleted - */ - path: string; - /** - * The message - for display purposes - e.g. The profile was successfully deleted. - * @type {string} - * @memberof IProfileDeleted - */ - message: string; - /** - * Specifies whether the default profile was cleared. - * @type {boolean} - * @memberof IProfileDeleted - */ - defaultCleared?: boolean; -} diff --git a/packages/imperative/src/profiles/src/doc/response/IProfileSaved.ts b/packages/imperative/src/profiles/src/doc/response/IProfileSaved.ts deleted file mode 100644 index d45bdb2e88..0000000000 --- a/packages/imperative/src/profiles/src/doc/response/IProfileSaved.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfile } from "../definition/IProfile"; -/** - * The success response to the profile "save()" API. - * @export - * @interface IProfileSaved - */ -export interface IProfileSaved { - /** - * The path that the new profile was written to - * @type {string} - * @memberof IProfileSaved - */ - path: string; - /** - * A message describing the result of the profile creation - for display purposes - * @type {string} - * @memberof IProfileSaved - */ - message: string; - /** - * True if the profile saved overwrote an existing profile of the same name/type. - * - * @type {boolean} - * @memberof IProfileSaved - */ - overwritten: boolean; - /** - * The contents of the profile saved. - * @type {IProfile} - * @memberof IProfileSaved - */ - profile?: IProfile; -} diff --git a/packages/imperative/src/profiles/src/doc/response/IProfileUpdated.ts b/packages/imperative/src/profiles/src/doc/response/IProfileUpdated.ts deleted file mode 100644 index 59921265ef..0000000000 --- a/packages/imperative/src/profiles/src/doc/response/IProfileUpdated.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -import { IProfile } from "../definition/IProfile"; -/** - * The success response to the profile "update()" API. - * @export - * @interface IProfileUpdated - */ -export interface IProfileUpdated { - /** - * The path to the profile that was updated - */ - path: string; - /** - * A message for display purposes - */ - message: string; - /** - * The contents of the profile - */ - profile?: IProfile; -} diff --git a/packages/imperative/src/profiles/src/doc/response/IProfileValidated.ts b/packages/imperative/src/profiles/src/doc/response/IProfileValidated.ts deleted file mode 100644 index f8ff020790..0000000000 --- a/packages/imperative/src/profiles/src/doc/response/IProfileValidated.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* -* This program and the accompanying materials are made available under the terms of the -* Eclipse Public License v2.0 which accompanies this distribution, and is available at -* https://www.eclipse.org/legal/epl-v20.html -* -* SPDX-License-Identifier: EPL-2.0 -* -* Copyright Contributors to the Zowe Project. -* -*/ - -/** - * The success response to the profile "validate()" APi. - * @export - * @interface IProfileValidated - */ -export interface IProfileValidated { - /** - * Message - for display purposes - e.g. The profile was updated. - * @type {string} - * @memberof IProfileValidated - */ - message: string; -} diff --git a/packages/imperative/src/profiles/src/doc/response/index.ts b/packages/imperative/src/profiles/src/doc/response/index.ts index e3aacce2b8..48c60a0eb6 100644 --- a/packages/imperative/src/profiles/src/doc/response/index.ts +++ b/packages/imperative/src/profiles/src/doc/response/index.ts @@ -9,9 +9,4 @@ * */ -export * from "./IProfileDeleted"; export * from "./IProfileLoaded"; -export * from "./IProfileSaved"; -export * from "./IProfileUpdated"; -export * from "./IProfileValidated"; - diff --git a/packages/imperative/src/profiles/src/utils/ProfileIO.ts b/packages/imperative/src/profiles/src/utils/ProfileIO.ts index 41f7419d19..ebda18db90 100644 --- a/packages/imperative/src/profiles/src/utils/ProfileIO.ts +++ b/packages/imperative/src/profiles/src/utils/ProfileIO.ts @@ -312,7 +312,7 @@ export class ProfileIO { private static crashInTeamConfigMode() { if (ImperativeConfig.instance.config?.exists) { try { - throw new Error("A Zowe V1 profile operation was attempted with a Zowe V2 configuration in use."); + throw new Error("A Zowe V1 profile operation was attempted with a Zowe team configuration in use."); } catch (err) { throw new ImperativeError({ msg: err.message, diff --git a/packages/imperative/src/profiles/src/utils/ProfileUtils.ts b/packages/imperative/src/profiles/src/utils/ProfileUtils.ts index 73d7db4d3f..d38aa308d4 100644 --- a/packages/imperative/src/profiles/src/utils/ProfileUtils.ts +++ b/packages/imperative/src/profiles/src/utils/ProfileUtils.ts @@ -18,6 +18,7 @@ import * as nodePath from "path"; * Set of static utility methods to assist with creating profile option names from profile types, constructing the * root directory, reforming responses for different purposes, etc. * + * @internal * @export * @class ProfileUtils */ diff --git a/packages/imperative/src/profiles/src/utils/__mocks__/ProfileIO.ts b/packages/imperative/src/profiles/src/utils/__mocks__/ProfileIO.ts index 423850240b..02ef409757 100644 --- a/packages/imperative/src/profiles/src/utils/__mocks__/ProfileIO.ts +++ b/packages/imperative/src/profiles/src/utils/__mocks__/ProfileIO.ts @@ -28,7 +28,7 @@ import { ORANGE_PROFILE_TYPE, STRAWBERRY_PROFILE_TYPE, STRAWBERRY_TYPE_SCHEMA -} from "../../../__tests__/TestConstants"; +} from "../../../../cmd/__tests__/profiles/TestConstants"; import { IProfileTypeConfiguration } from "../../doc/config/IProfileTypeConfiguration"; /** diff --git a/packages/imperative/src/profiles/src/utils/__tests__/ProfileIO.unit.test.ts b/packages/imperative/src/profiles/src/utils/__tests__/ProfileIO.unit.test.ts index 3db343555c..e434c42096 100644 --- a/packages/imperative/src/profiles/src/utils/__tests__/ProfileIO.unit.test.ts +++ b/packages/imperative/src/profiles/src/utils/__tests__/ProfileIO.unit.test.ts @@ -26,7 +26,7 @@ import { BLUEBERRY_PROFILE_TYPE, BLUEBERRY_TYPE_SCHEMA, STRAWBERRY_PROFILE_TYPE -} from "../../../__tests__/TestConstants"; +} from "../../../../cmd/__tests__/profiles/TestConstants"; import { IMetaProfile, IProfile } from "../../../../index"; import { IProfileTypeConfiguration } from "../../doc/config/IProfileTypeConfiguration"; import { ImperativeConfig } from "../../../../utilities"; @@ -439,7 +439,7 @@ describe("Profile IO", () => { expect(error.message).toContain("Error Details: IO ERROR!"); }); describe("Profile operations should crash in team-config mode", () => { - const configModeErr = "Profile IO Error: A Zowe V1 profile operation was attempted with a Zowe V2 configuration in use."; + const configModeErr = "Profile IO Error: A Zowe V1 profile operation was attempted with a Zowe team configuration in use."; beforeEach(() => { /* Pretend that we have a team config. diff --git a/packages/imperative/src/profiles/src/utils/__tests__/ProfileUtils.unit.test.ts b/packages/imperative/src/profiles/src/utils/__tests__/ProfileUtils.unit.test.ts index c645aeb82d..bfec2d8667 100644 --- a/packages/imperative/src/profiles/src/utils/__tests__/ProfileUtils.unit.test.ts +++ b/packages/imperative/src/profiles/src/utils/__tests__/ProfileUtils.unit.test.ts @@ -14,7 +14,9 @@ jest.mock("path"); import { ProfileUtils } from "../ProfileUtils"; import * as path from "path"; import { IProfileLoaded } from "../../../../index"; -import { APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP, BLUEBERRY_PROFILE_TYPE } from "../../../__tests__/TestConstants"; +import { + APPLE_TWO_REQ_DEP_BANANA_ONE_REQ_DEP_GRAPE_ONE_REQ_DEP, BLUEBERRY_PROFILE_TYPE +} from "../../../../cmd/__tests__/profiles/TestConstants"; const mocks = { normalize: path.normalize as unknown as Mock diff --git a/packages/imperative/src/profiles/src/validation/api/ProfileValidator.ts b/packages/imperative/src/profiles/src/validation/api/ProfileValidator.ts index fdec3318ef..6b4dc0f79a 100644 --- a/packages/imperative/src/profiles/src/validation/api/ProfileValidator.ts +++ b/packages/imperative/src/profiles/src/validation/api/ProfileValidator.ts @@ -28,6 +28,7 @@ import { CliUtils } from "../../../../utilities/src/CliUtils"; /** * API for going through the full validation test for a Zowe CLI profile * and producing validation report + * @internal */ export class ProfileValidator { diff --git a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts index 5bb3ad2888..278c2c2fea 100644 --- a/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts +++ b/packages/imperative/src/rest/src/session/ConnectionPropsForSessCfg.ts @@ -352,6 +352,31 @@ export class ConnectionPropsForSessCfg { */ private static getValuesBack(connOpts: IOptionsForAddConnProps): (properties: string[]) => Promise<{ [key: string]: any }> { return async (promptForValues: string[]) => { + /* ToDo: Uncomment this code block to display an informative message before prompting + * a user for connection values. Because 219 unit test fails and 144 system tests + * fail due to a minor difference in output, we chose not to implement this + * minor enhancement until we have time to devote to correcting so many tests. + * + * The following 'if' statement is only needed for tests which do not create a mock for + * the connOpts.parms.response.console.log property. In the real world, that property + * always exists for this CLI-only path of logic. + * + if (connOpts?.parms?.response?.console?.log) { + // we want to prompt for connection values, but first complain if user only has V1 profiles. + connOpts.parms.response.console.log("No Zowe client configuration exists."); + if (ConfigUtils.onlyV1ProfilesExist) { + connOpts.parms.response.console.log( + "Only V1 profiles exist. V1 profiles are no longer supported.\n" + + "You should convert your V1 profiles to a Zowe client team configuration." + ); + } + connOpts.parms.response.console.log( + "Therefore, you will be asked for the connection properties\n" + + "that are required to complete your command.\n" + ); + } + */ + const answers: { [key: string]: any } = {}; const profileSchema = this.loadSchemaForSessCfgProps(connOpts.parms, promptForValues); const serviceDescription = connOpts.serviceDescription || "your service"; diff --git a/packages/imperative/src/utilities/src/CliUtils.ts b/packages/imperative/src/utilities/src/CliUtils.ts index e4cb9fc4e3..435eb96e65 100644 --- a/packages/imperative/src/utilities/src/CliUtils.ts +++ b/packages/imperative/src/utilities/src/CliUtils.ts @@ -22,6 +22,7 @@ import { IProfile } from "../../profiles"; import { IPromptOptions } from "../../cmd/src/doc/response/api/handler/IPromptOptions"; import { read } from "read"; + /** * Cli Utils contains a set of static methods/helpers that are CLI related (forming options, censoring args, etc.) * @export @@ -105,7 +106,7 @@ export class CliUtils { /** * Accepts the full set of loaded profiles and attempts to match the option names supplied with profile keys. * - * @param {Map} profileMap - the map of type to loaded profiles. The key is the profile type + * @param {Map} profiles - the map of type to loaded profiles. The key is the profile type * and the value is an array of profiles loaded for that type. * * @param {definitions} definitions - the profile definition on the command. diff --git a/packages/zosfiles/CHANGELOG.md b/packages/zosfiles/CHANGELOG.md index d6e31e4b04..08c141c81c 100644 --- a/packages/zosfiles/CHANGELOG.md +++ b/packages/zosfiles/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to the Zowe z/OS files SDK package will be documented in thi ## `8.0.0-next.202402021649` +- LTS Breaking: Removed the unused protected property `mSshProfile` in SshBaseHandler. - LTS Breaking: Removed the following previously deprecated items: - Removed `ZosFilesCreateExtraOptions.showAttributes` without replacement - Removed `allDataSetsArchived`, `datasetsDownloadedSuccessfully`, `noDataSetsMatchingPatternRemain` and `onlyEmptyPartitionedDataSets` from ZosFiles.messages.ts diff --git a/packages/zosmf/CHANGELOG.md b/packages/zosmf/CHANGELOG.md index fc48cbc0c2..f861358371 100644 --- a/packages/zosmf/CHANGELOG.md +++ b/packages/zosmf/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to the Zowe z/OSMF SDK package will be documented in this fi ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- LTS Breaking: Removed the following obsolete V1 profile constants from ZosmfProfile.schema.properties + - createProfileExamples + - updateProfileExamples ## `8.0.0-next.202402261705` diff --git a/packages/zosmf/src/ZosmfBaseHandler.ts b/packages/zosmf/src/ZosmfBaseHandler.ts index b7a5dcbe3a..c2203cd23d 100644 --- a/packages/zosmf/src/ZosmfBaseHandler.ts +++ b/packages/zosmf/src/ZosmfBaseHandler.ts @@ -69,8 +69,6 @@ export abstract class ZosmfBaseHandler implements ICommandHandler { public async process(commandParameters: IHandlerParameters) { this.mHandlerParams = commandParameters; - this.mZosmfProfile = commandParameters.profiles.get("zosmf", false); - this.mZosmfLoadedProfile = commandParameters.profiles.getMeta("zosmf", false); const sessCfg: ISession = ZosmfSession.createSessCfgFromArgs( commandParameters.arguments diff --git a/packages/zosmf/src/constants/Zosmf.profile.ts b/packages/zosmf/src/constants/Zosmf.profile.ts index 4d7fc0a941..822cf94a6c 100644 --- a/packages/zosmf/src/constants/Zosmf.profile.ts +++ b/packages/zosmf/src/constants/Zosmf.profile.ts @@ -86,40 +86,5 @@ export const ZosmfProfile: ICommandProfileTypeConfiguration = } }, required: [] - }, - createProfileExamples: [ - { - options: "zos123 --host zos123 --port 1443 --user ibmuser --password myp4ss", - description: "Create a zosmf profile called 'zos123' to connect to z/OSMF at host zos123 and port 1443" - }, - { - options: "zos124 --host zos124 --user ibmuser --password myp4ss --reject-unauthorized false", - description: "Create a zosmf profile called 'zos124' to connect to z/OSMF at the host zos124 (default port - 443) " + - "and allow self-signed certificates" - }, - { - options: "zos125 --host zos125 --port 1443", - description: "Create a zosmf profile called 'zos125' to connect to z/OSMF at the host zos125 and port 1443, " + - " not specifying a username or password so they are not stored on disk; these will need to be specified on every command" - }, - { - options: "zos126 --reject-unauthorized false", - description: "Create a zosmf profile called 'zos126' to connect to z/OSMF on the default port 443 and allow self-signed " + - "certificates, not specifying a username, password, or host so they are not stored on disk; these will need to be " + - "specified on every command" - }, - { - options: "zosAPIML --host zosAPIML --port 7554 --user ibmuser --password myp4ss --reject-unauthorized false --base-path ibmzosmf/api/v1", - description: "Create a zosmf profile called 'zosAPIML' to connect to z/OSMF via the Zowe API Mediation Layer running at host " + - "'zosAPIML', port '7554', and allow for self-signed certificates. To reduce duplication, you could elect to store the 'host', " + - "'port', 'reject-unauthorized', 'user', and 'password' values for the API Mediation Layer in a base profile and only store " + - "the 'base-path' of the service in the zosmf profile" - } - ], - updateProfileExamples: [ - { - options: "zos123 --user newuser --password newp4ss", - description: "Update a zosmf profile named 'zos123' with a new username and password" - } - ] + } }; diff --git a/packages/zostso/CHANGELOG.md b/packages/zostso/CHANGELOG.md index 74ad57db00..3f0101e388 100644 --- a/packages/zostso/CHANGELOG.md +++ b/packages/zostso/CHANGELOG.md @@ -5,6 +5,9 @@ All notable changes to the Zowe z/OS TSO SDK package will be documented in this ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- LTS Breaking: Removed the following obsolete V1 profile constants from ZosTsoProfile.schema.properties + - createProfileExamples + - updateProfileExamples ## `8.0.0-next.202402261705` diff --git a/packages/zostso/src/constants/ZosTso.profile.ts b/packages/zostso/src/constants/ZosTso.profile.ts index 67ed8955e0..21b407ce98 100644 --- a/packages/zostso/src/constants/ZosTso.profile.ts +++ b/packages/zostso/src/constants/ZosTso.profile.ts @@ -57,27 +57,5 @@ export const ZosTsoProfile: ICommandProfileTypeConfiguration = { } }, required: [] - }, - createProfileExamples: [ - { - description: "Create a tso profile called 'myprof' with default settings and JES accounting information of 'IZUACCT'", - options: "myprof -a IZUACCT" - }, - { - description: "Create a tso profile called 'largeregion' with a region size of 8192, a logon procedure of MYPROC, and " + - "JES accounting information of '1234'", - options: "largeregion -a 1234 --rs 8192" - }, - { - description: "Create a tso profile called 'myprof2' with default settings and region size of 8192, without storing the user " + - "account on disk", - options: "myprof2 --rs 8192" - } - ], - updateProfileExamples: [ - { - description: "Update a tso profile called myprof with new JES accounting information", - options: "myprof -a NEWACCT" - } - ] + } }; diff --git a/packages/zosuss/CHANGELOG.md b/packages/zosuss/CHANGELOG.md index db79934f37..9dbc5e87c2 100644 --- a/packages/zosuss/CHANGELOG.md +++ b/packages/zosuss/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to the Zowe z/OS USS SDK package will be documented in this ## Recent Changes - BugFix: Updated engine to Node 18.12.0. [#2074](https://github.com/zowe/zowe-cli/pull/2074) +- LTS Breaking: Removed the following obsolete V1 profile constant from ZosUssProfile.schema.properties + - createProfileExamples ## `8.0.0-next.202402261705` diff --git a/packages/zosuss/src/SshBaseHandler.ts b/packages/zosuss/src/SshBaseHandler.ts index 0b4edc9daf..156af231b1 100644 --- a/packages/zosuss/src/SshBaseHandler.ts +++ b/packages/zosuss/src/SshBaseHandler.ts @@ -15,7 +15,6 @@ import { ICommandHandler, IOverridePromptConnProps, IHandlerParameters, - IProfile, IHandlerResponseConsoleApi, IHandlerFormatOutputApi, IHandlerResponseDataApi, @@ -38,11 +37,6 @@ export abstract class SshBaseHandler implements ICommandHandler { */ protected mSession: SshSession; - /** - * Loaded z/OS SSH profile if needed - */ - protected mSshProfile: IProfile; - /** * Command line arguments passed */ @@ -63,7 +57,6 @@ export abstract class SshBaseHandler implements ICommandHandler { */ public async process(commandParameters: IHandlerParameters) { this.mHandlerParams = commandParameters; - this.mSshProfile = commandParameters.profiles.get("ssh", false); const sshSessCfgOverride: IOverridePromptConnProps[] = [{ propertyName: "privateKey", diff --git a/packages/zosuss/src/constants/ZosUss.profile.ts b/packages/zosuss/src/constants/ZosUss.profile.ts index 472526ec6c..6014778571 100644 --- a/packages/zosuss/src/constants/ZosUss.profile.ts +++ b/packages/zosuss/src/constants/ZosUss.profile.ts @@ -58,26 +58,5 @@ export const ZosUssProfile: ICommandProfileTypeConfiguration = { } }, required: [] - }, - createProfileExamples: [ - { - options: "ssh111 --host sshhost --user ibmuser --password myp4ss", - description: "Create a ssh profile called 'ssh111' to connect to z/OS SSH server at host 'zos123' and default port 22" - }, - { - options: "ssh222 --host sshhost --port 13022 --user ibmuser --password myp4ss", - description: "Create a ssh profile called 'ssh222' to connect to z/OS SSH server at host 'zos123' and port 13022" - }, - { - options: "ssh333 --host sshhost --user ibmuser --privateKey /path/to/privatekey --keyPassphrase privateKeyPassphrase", - description: "Create a ssh profile called 'ssh333' to connect to z/OS SSH server at host 'zos123' " + - "using a privatekey '/path/to/privatekey' and its decryption passphrase 'privateKeyPassphrase' " + - "for privatekey authentication" - }, - { - options: "ssh444 --privateKey /path/to/privatekey", - description: "Create a ssh profile called 'ssh444' to connect to z/OS SSH server on default port 22, without specifying " + - "username, host, or password, preventing those values from being stored on disk" - } - ] + } };