Skip to content

Commit

Permalink
Merge pull request #2994 from zowe/ext-not
Browse files Browse the repository at this point in the history
feat: Leverage Imperative's event handling capabilities and more...
  • Loading branch information
zFernand0 authored Aug 1, 2024
2 parents a92b002 + 2bccce9 commit 49951e8
Show file tree
Hide file tree
Showing 69 changed files with 947 additions and 763 deletions.
21 changes: 16 additions & 5 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,18 @@ plugins:
rules:
"@typescript-eslint/await-thenable": off
"@typescript-eslint/consistent-type-assertions": warn
"@typescript-eslint/explicit-function-return-type": error
"@typescript-eslint/explicit-function-return-type": [ 'error', {
# We only disallow the rules that provide value (i.e. that found some errors while configuring)
# Documentation: https://typescript-eslint.io/rules/explicit-function-return-type
allowHigherOrderFunctions: false,
allowFunctionsWithoutTypeParameters: false,

# Disabling (i.e. setting to `false`) the following rule will force us to unnecessarily type built-in functions
# For example, to find the index of a profile in a profiles array we will have to go:
# FROM: profiles.findIndex((profile) => profile.name === "my_profile"))
# TO: profiles.findIndex((profile): boolean => profile.name === "my_profile"))
allowTypedFunctionExpressions: true,
}]
"@typescript-eslint/explicit-member-accessibility": error

# There are several errors falling under these rules; resolve
Expand All @@ -46,9 +57,9 @@ rules:
"@typescript-eslint/no-unused-expressions": error
"@typescript-eslint/no-var-requires": warn
array-callback-return: error
complexity:
- warn
- 15
# complexity:
# - warn
# - 15
constructor-super: error
curly: warn
getter-return: error
Expand All @@ -69,7 +80,7 @@ rules:
no-irregular-whitespace: warn
no-magic-numbers:
- warn
- "ignore": [-1, 0, 1, 2, 4]
- "ignore": [-2, -1, 0, 1, 2, 4]
no-multiple-empty-lines: warn
no-return-await: warn
no-sequences: warn
Expand Down
6 changes: 5 additions & 1 deletion packages/zowe-explorer-api/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@ All notable changes to the "zowe-explorer-api" extension will be documented in t
- Added PEM certificate support as an authentication method for logging into the API ML. [#2621](https://github.com/zowe/zowe-explorer-vscode/issues/2621)
- Deprecated the `getUSSDocumentFilePath` function on the `IZoweTreeNode` interface as Zowe Explorer no longer uses the local file system for storing USS files. **No replacement is planned**; please access data from tree nodes using their [resource URIs](https://github.com/zowe/zowe-explorer-vscode/wiki/FileSystemProvider#operations-for-extenders) instead. [#2968](https://github.com/zowe/zowe-explorer-vscode/pull/2968)
- **Next Breaking:** Changed `ProfilesCache.convertV1ProfToConfig` method to be a static method that requires `ProfileInfo` instance as a parameter.
- Added the `onVaultUpdate` VSCode event to notify extenders when credentials are updated on the OS vault by other applications. [#2994](https://github.com/zowe/zowe-explorer-vscode/pull/2994)
- Added the `onCredMgrsUpdate` VSCode event to notify extenders when the local PC's credential manager has been updated by other applications. [#2994](https://github.com/zowe/zowe-explorer-vscode/pull/2994)
- Updated most function signatures for exported programmatic interfaces. Changes make developing with the Zowe Explorer API more efficient for extenders by showing which properties they can expect when calling our APIs. [#2952](https://github.com/zowe/zowe-explorer-vscode/issues/2952)

### Bug fixes

- Fixed an issue where the `onProfilesUpdate` event did not fire after secure credentials were updated. [#2822](https://github.com/zowe/zowe-explorer-vscode/issues/2822)
- Fixed an issue where `ProfilesCache` may return missing or incorrect profile values when multiple extensions call it during activation. [#2831](https://github.com/zowe/zowe-explorer-vscode/issues/2831)
- Removed `handlebars` dependency in favor of `mustache` for technical currency purposes. [#2975](https://github.com/zowe/zowe-explorer-vscode/pull/2975)
- Update Zowe SDKs to `8.0.0-next.202407051717` for technical currency. [#2918](https://github.com/zowe/zowe-explorer-vscode/issues/2918)
- Fixed an issue where the `ZoweVsCodeExtension.updateCredentials` method could remove credentials from session when input prompt was cancelled. [#3009](https://github.com/zowe/zowe-explorer-vscode/pull/3009)
- Fixed an issue where the loaded configuration could be overridden when extenders retrieved the Zowe home directory. [#2994](https://github.com/zowe/zowe-explorer-vscode/pull/2994)
- Update Zowe SDKs to `8.0.0-next.202407232256` for technical currency. [#2994](https://github.com/zowe/zowe-explorer-vscode/pull/2994)

## `3.0.0-next.202404242037`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { BaseProvider, ConflictViewSelection, DirEntry, FileEntry, ZoweScheme }
import { Gui } from "../../../src/globals";
import { MockedProperty } from "../../../__mocks__/mockUtils";

function getGlobalMocks() {
function getGlobalMocks(): { [key: string]: any } {
return {
testFileUri: vscode.Uri.from({ scheme: ZoweScheme.USS, path: "/file.txt" }),
testFolderUri: vscode.Uri.from({ scheme: ZoweScheme.USS, path: "/folder" }),
Expand Down Expand Up @@ -42,7 +42,7 @@ function getGlobalMocks() {
const globalMocks = getGlobalMocks();

describe("diffOverwrite", () => {
function getBlockMocks() {
function getBlockMocks(): { [key: string]: jest.SpyInstance<any> } {
return {
lookupAsFileMock: jest.spyOn((BaseProvider as any).prototype, "_lookupAsFile"),
writeFileMock: jest.spyOn(vscode.workspace.fs, "writeFile").mockImplementation(),
Expand Down Expand Up @@ -88,7 +88,7 @@ describe("diffOverwrite", () => {
});

describe("diffUseRemote", () => {
function getBlockMocks(prov) {
function getBlockMocks(prov): { [key: string]: jest.SpyInstance<any> } {
return {
lookupAsFileMock: jest.spyOn(prov, "_lookupAsFile"),
writeFileMock: jest.spyOn(vscode.workspace.fs, "writeFile").mockImplementation(),
Expand Down Expand Up @@ -161,7 +161,7 @@ describe("diffUseRemote", () => {
});

describe("exists", () => {
function getBlockMocks() {
function getBlockMocks(): { [key: string]: jest.SpyInstance<any> } {
return {
lookupMock: jest.spyOn((BaseProvider as any).prototype, "_lookup"),
};
Expand Down Expand Up @@ -454,7 +454,7 @@ describe("_createFile", () => {
}
});

it("throws an error if a folder already exists with the same URI", async () => {
it("throws an error if a folder already exists with the same URI", () => {
const prov = new (BaseProvider as any)();
prov.root = new DirEntry("");
prov.root.metadata = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as vscode from "vscode";
import { Constants } from "../../../src/globals";
jest.mock("vscode");

function createGlobalMocks() {
function createGlobalMocks(): { [key: string]: jest.Mock } {
const mocks = {
showInfoMessage: jest.fn(),
showErrorMessage: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ import { FileManagement, Types } from "../../../src";

jest.mock("fs");

const fakeSchema: { properties: object } = {
properties: {
host: { type: "string" },
port: { type: "number" },
user: { type: "string", secure: true },
password: { type: "string", secure: true },
},
};
const lpar1Profile: Required<Pick<imperative.IProfileLoaded, "name" | "type" | "profile">> = {
name: "lpar1",
type: "zosmf",
Expand Down Expand Up @@ -157,7 +149,7 @@ describe("ProfilesCache", () => {
existsSync.mockRestore();
});

it("requireKeyring returns keyring module from Secrets SDK", async () => {
it("requireKeyring returns keyring module from Secrets SDK", () => {
const keyring = ProfilesCache.requireKeyring();
expect(keyring).toBeDefined();
expect(Object.keys(keyring).length).toBe(5);
Expand Down Expand Up @@ -260,7 +252,7 @@ describe("ProfilesCache", () => {

it("should refresh profile data for multiple profile types", async () => {
const profCache = new ProfilesCache({ ...fakeLogger, error: mockLogError } as unknown as imperative.Logger);
const getProfInfoSpy = jest.spyOn(profCache, "getProfileInfo").mockResolvedValue(createProfInfoMock([lpar1Profile, zftpProfile]));
jest.spyOn(profCache, "getProfileInfo").mockResolvedValue(createProfInfoMock([lpar1Profile, zftpProfile]));
await profCache.refresh(fakeApiRegister as unknown as Types.IApiRegisterClient);
expect(profCache.allProfiles.length).toEqual(2);
expect(profCache.allProfiles[0]).toMatchObject(lpar1Profile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,11 @@ async function expectUnixCommandApiWithSshSession<T>(
): Promise<void> {
spy.mockClear().mockResolvedValue(undefined);
spy.mockImplementation((sshobject: zosuss.SshSession, command: string, cwd: string, callback: (data: string) => void) => {
let r = "";
callback("test");
r += "test";
});
const spywhenpathnotspecified = jest.spyOn(zosuss.Shell, "executeSsh");
spywhenpathnotspecified.mockImplementation((sshobject: zosuss.SshSession, command: string, callback: (data: string) => void) => {
let r = "";
callback("test");
r += "test";
});
await apiInstance[name as string](sshobj, ...args, true, () => {});
await apiInstance[name as string](sshobj, ...args, false, () => {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@ describe("ZoweVsCodeExtension", () => {
const testSpy = jest.spyOn(ZoweVsCodeExtension as any, "getServiceProfileForAuthPurposes");
jest.spyOn(ZoweVsCodeExtension as any, "promptUserPass").mockResolvedValue(["user", "pass"]);
let sessionCopy;
const loginSpy = jest.spyOn(Login, "apimlLogin").mockImplementation(async (session: imperative.Session) => {
const loginSpy = jest.spyOn(Login, "apimlLogin").mockImplementation((session: imperative.Session) => {
sessionCopy = Object.assign(Object.create(Object.getPrototypeOf(session)), session);
return "tokenValue";
return Promise.resolve("tokenValue");
});

// case 1: User selects "user/password" for login quick pick
Expand Down
26 changes: 15 additions & 11 deletions packages/zowe-explorer-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,30 @@
},
"dependencies": {
"@types/vscode": "^1.53.2",
"@zowe/core-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/imperative": "8.0.0-next.202407051717",
"@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407051717",
"@zowe/core-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/imperative": "8.0.0-next.202407232256",
"@zowe/secrets-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202407232256",
"@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202407232256",
"mustache": "^4.2.0",
"semver": "^7.6.0"
},
"scripts": {
"build": "pnpm check-cli && pnpm copy-secrets && pnpm clean && pnpm license && tsc -p ./ && pnpm madge",
"test:unit": "jest \".*__tests__.*\\.unit\\.test\\.ts\" --coverage",
"test": "pnpm test:unit",
"lint": "concurrently -n \"_eslint_,prettier\" \"eslint .\" \"prettier --write . && prettier --check .\"",
"lint:html": "eslint . --format html > results/eslint.html",
"lint": "concurrently -n \"_eslint_,prettier\" \"pnpm lint:all\" \"pnpm pretty; pnpm pretty:check\"",
"lint:all": "pnpm lint:src; pnpm lint:test; pnpm lint:html",
"lint:src": "eslint --format stylish src/**/*.ts",
"lint:test": "eslint --format stylish __tests__/**/*.ts",
"lint:html": "mkdir -p results && eslint . --format html > results/eslint.html",
"madge": "madge -c --no-color --no-spinner --exclude __mocks__ --extensions js,ts src/",
"pretty": "prettier --write .",
"pretty:check": "prettier --check .",
"check-cli": "node scripts/check-cli.js",
"clean": "rimraf lib tsconfig.tsbuildinfo",
"fresh-clone": "pnpm clean && (rimraf node_modules || true)",
Expand Down
34 changes: 22 additions & 12 deletions packages/zowe-explorer-api/src/extend/IRegisterClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ import * as vscode from "vscode";
* the object returned by this extensions activate() method as shown below.
*
* @example
* // see if Zowe Explorer is installed and retrieve the API Registry\
* const explorerApi = extensions.getExtension('zowe.vscode-extension-for-zowe');\
* if (explorerApi && explorerApi.exports) {\
* // Cast the returned object to the IApiRegisterClient interface\
* const importedApi: IApiRegisterClient = explorerApi.exports;\
* // create an instance of my API and register it with Zowe Explorer\
* importedApi.registerUssApi(new MyZoweExplorerAppUssApi());\
* window.showInformationMessage(\
* 'Zowe Explorer was augmented for MyApp support. Please, refresh your explorer views.');\
* } else {\
* window.showInformationMessage(\
* 'Zowe VS Extension was not found: either not installe or older version.');\
* // see if Zowe Explorer is installed and retrieve the API Registry
* const explorerApi = extensions.getExtension('zowe.vscode-extension-for-zowe');
* if (explorerApi && explorerApi.exports) {
* // Cast the returned object to the IApiRegisterClient interface
* const importedApi: IApiRegisterClient = explorerApi.exports;
* // create an instance of my API and register it with Zowe Explorer
* importedApi.registerUssApi(new MyZoweExplorerAppUssApi());
* window.showInformationMessage(
* 'Zowe Explorer was augmented for MyApp support. Please, refresh your explorer views.');
* } else {
* window.showInformationMessage(
* 'Zowe VS Extension was not found: either not installed or older version.');
* }
*
* @export
Expand Down Expand Up @@ -110,6 +110,16 @@ export interface IRegisterClient {
*/
onProfilesUpdate?: vscode.Event<Validation.EventType>;

/**
* Define events that fire whenever credentials are updated on the client.
*/
onVaultUpdate?: vscode.Event<Validation.EventType>;

/**
* Define events that fire whenever the credential manager is updated.
*/
onCredMgrUpdate?: vscode.Event<Validation.EventType>;

/**
* Lookup of any registered API (Uss, Mvs, Jes, or Command).
* @param {string} profile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,8 @@ export namespace ZoweExplorerZosmf {
};
}
} else {
// If we decide to match 1:1 the Zowe.Copy.dataSet implementation, we will need to break the interface definition in the ZoweExplorerApi
// If we decide to match 1:1 the Zowe.Copy.dataSet implementation,
// we will need to break the interface definition in the ZoweExplorerApi
newOptions = { "from-dataset": { dsn: fromDataSetName, member: fromMemberName } };
}
return zosfiles.Copy.dataSet(this.getSession(), { dsn: toDataSetName, member: toMemberName }, newOptions);
Expand Down
7 changes: 5 additions & 2 deletions packages/zowe-explorer-api/src/utils/FileManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import { realpathSync } from "fs";
import { platform } from "os";
import { Constants } from "../globals";
import { ProfileInfo } from "@zowe/imperative";
import { ImperativeConfig, ConfigUtils } from "@zowe/imperative";

export class FileManagement {
public static permStringToOctal(perms: string): number {
Expand All @@ -34,7 +34,10 @@ export class FileManagement {
}

public static getZoweDir(): string {
return ProfileInfo.getZoweDir();
if (ImperativeConfig.instance.loadedConfig != null) {
return ImperativeConfig.instance.cliHome;
}
return ConfigUtils.getZoweDir();
}

public static getFullPath(anyPath: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export class ZoweVsCodeExtension {
const saveButton = "Save Credentials";
const message = [
`Save entered credentials in plain text for future use with profile ${profile.name}?`,
"Saving credentials will update the local information file.",
"Saving credentials will update the local configuration file.",
].join("\n");
await Gui.showMessage(message, { items: [saveButton], vsCodeOpts: { modal: true } }).then((selection) => {
if (selection) {
Expand Down
2 changes: 1 addition & 1 deletion packages/zowe-explorer-ftp-extension/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ All notable changes to the "zowe-explorer-ftp-extension" extension will be docum

- Changed the hashing algorithm for e-tag generation from `sha1` to `sha256` to avoid collisions. [#2890](https://github.com/zowe/zowe-explorer-vscode/pull/2890)
- Updated the FTP plugin dependency to `3.0.0-next.202403191358` for technical currency [#2783](https://github.com/zowe/vscode-extension-for-zowe/pull/2783).
- Update Zowe SDKs to `8.0.0-next.202405241828` for technical currency. [#2918](https://github.com/zowe/zowe-explorer-vscode/issues/2918)
- Update Zowe SDKs to `8.0.0-next.202407232256` for technical currency. [#2994](https://github.com/zowe/zowe-explorer-vscode/pull/2994)

## `3.0.0-next.202404242037`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe("AbstractFtpApi", () => {
it("should show a fatal message when trying to call getStatus with invalid credentials.", async () => {
Object.defineProperty(Gui, "errorMessage", { value: jest.fn(), configurable: true });
jest.spyOn(FTPConfig, "connectFromArguments").mockImplementationOnce(
jest.fn((val) => {
jest.fn((_val) => {
throw new Error("Failed: missing credentials");
})
);
Expand All @@ -95,7 +95,7 @@ describe("AbstractFtpApi", () => {
it("should show a different fatal message when trying to call getStatus and an exception occurs.", async () => {
Object.defineProperty(Gui, "errorMessage", { value: jest.fn(), configurable: true });
jest.spyOn(FTPConfig, "connectFromArguments").mockImplementationOnce(
jest.fn((prof) => {
jest.fn((_prof) => {
throw new Error("Something happened");
})
);
Expand Down Expand Up @@ -142,7 +142,7 @@ describe("AbstractFtpApi", () => {
Object.defineProperty(Gui, "showMessage", { value: jest.fn(), configurable: true });
const instance = new Dummy(profile);
jest.spyOn(FTPConfig, "connectFromArguments").mockImplementationOnce(
jest.fn(((prof) => Promise.resolve({ test: "Test successful object" })) as any)
jest.fn(((_prof) => Promise.resolve({ test: "Test successful object" })) as any)
);

const status = await instance.getStatus(profile, "zftp");
Expand All @@ -152,7 +152,7 @@ describe("AbstractFtpApi", () => {
it("should return inactive from sessionStatus when getStatus is called w/ correct profile", async () => {
Object.defineProperty(Gui, "showMessage", { value: jest.fn(), configurable: true });
const instance = new Dummy(profile);
jest.spyOn(FTPConfig, "connectFromArguments").mockImplementationOnce(jest.fn(((prof) => Promise.resolve(false)) as any));
jest.spyOn(FTPConfig, "connectFromArguments").mockImplementationOnce(jest.fn(((_prof) => Promise.resolve(false)) as any));

const status = await instance.getStatus(profile, "zftp");
expect(status).toStrictEqual("inactive");
Expand Down
Loading

0 comments on commit 49951e8

Please sign in to comment.