Skip to content

Commit

Permalink
Merge branch 'main' into fix/error-handling-saves
Browse files Browse the repository at this point in the history
Signed-off-by: Trae Yelovich <trae.yelovich@broadcom.com>
  • Loading branch information
traeok committed Oct 3, 2024
2 parents 2b1083c + b43eccb commit 4466a30
Showing 58 changed files with 1,320 additions and 551 deletions.
17 changes: 11 additions & 6 deletions .github/release.config.js
Original file line number Diff line number Diff line change
@@ -6,19 +6,24 @@ module.exports = {
level: "minor"
},
{
name: "release/2.*",
name: "v1-lts",
channel: "zowe-v1-lts",
level: "patch"
},
{
name: "v2-lts",
channel: "zowe-v2-lts",
level: "patch"
},
{
name: "release/3.*",
channel: "latest",
level: "patch"
},
{
name: "next",
prerelease: true,
}
// {
// name: "next",
// prerelease: true
// }
],
plugins: [
[
@@ -44,7 +49,7 @@ module.exports = {
{
$cwd: "packages/zowe-explorer-api",
aliasTags: {
"latest": ["zowe-v2-lts"],
"latest": ["zowe-v3-lts"],
},
npmPublish: true,
tarballDir: "dist",
4 changes: 2 additions & 2 deletions .github/workflows/deployment.yml
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@ on:
push:
branches:
- main
- maintenance
- next
- v1-lts
- v2-lts
- release/3.*
paths:
- .github/release.config.js
- .github/workflows/deployment.yml
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -32,4 +32,5 @@ packages/zowe-explorer/__tests__/__integration__/ci
!packages/zowe-explorer/__tests__/__integration__/ci/zowe.config.json
package.nls.*.json
bundle.l10n.*.json
bundle.l10n.json.template
zedc/target
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ Join our [Slack channel](https://slack.openmainframeproject.org/) to connect wit
Client-side prerequisites for development:

- Install [Node.js](https://nodejs.org/en/download/) v16.0 or later.
- Install [PNPM](https://pnpm.io/installation).
- Install [PNPM 8](https://pnpm.io/installation).

Host-side prerequisites for connection:

221 changes: 135 additions & 86 deletions docs/early-access/v3/Extenders.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "3.0.0-next-SNAPSHOT",
"version": "3.1.0-SNAPSHOT",
"command": {
"version": {
"forcePublish": true,
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -58,7 +58,9 @@
"webpack-cli": "^5.1.4"
},
"pnpm": {
"overrides": {}
"overrides": {
"ws": "^8.17.1"
}
},
"scripts": {
"clean": "pnpm -r clean",
9 changes: 7 additions & 2 deletions packages/eslint-plugin-zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,11 +6,16 @@ All notable changes to the "eslint-plugin-zowe-explorer" package will be documen

### Bug fixes

## `3.0.0-next.202409132122`
## `3.0.0`

### New features and enhancements

### Bug fixes
- Added placeholder `madge` script to `package.json` for workspace script to succeed.
- Migrated to new package manager PNPM from Yarn.

## `3.0.0-next.202409251932`

## `3.0.0-next.202409132122`

## `3.0.0-next.202409091409`

2 changes: 1 addition & 1 deletion packages/eslint-plugin-zowe-explorer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-zowe-explorer",
"version": "3.0.0-next-SNAPSHOT",
"version": "3.1.0-SNAPSHOT",
"description": "Custom ESLint Rules for ZOWE Explorer",
"keywords": [
"eslint",
163 changes: 163 additions & 0 deletions packages/zowe-explorer-api/CHANGELOG.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -87,11 +87,12 @@ function createProfInfoMock(profiles: Partial<imperative.IProfileLoaded>[]): imp
const teamConfigApi: Partial<imperative.Config> = {
api: {
profiles: {
get: jest.fn().mockReturnValue({}),
get: jest.fn(),
getProfilePathFromName: jest.fn().mockImplementation((x) => x),
},
secure: {
secureFields: jest.fn().mockReturnValue([]),
securePropsForProfile: jest.fn().mockReturnValue([]),
},
} as any,
exists: true,
@@ -223,6 +224,7 @@ describe("ProfilesCache", () => {
profCache.allProfiles = [lpar1Profile as imperative.IProfileLoaded];
(profCache as any).defaultProfileByType = new Map([["zosmf", { ...profCache.allProfiles[0] }]]);
expect(profCache.allProfiles[0].profile).toMatchObject(lpar1Profile.profile);
// eslint-disable-next-line deprecation/deprecation
profCache.updateProfilesArrays({
...lpar1Profile,
profile: lpar2Profile.profile,
@@ -231,6 +233,35 @@ describe("ProfilesCache", () => {
expect((profCache as any).defaultProfileByType.get("zosmf").profile).toMatchObject(lpar2Profile.profile);
});

it("updateCachedProfile should refresh all profiles when autoStore is true", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as imperative.Logger);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValueOnce({
getTeamConfig: jest.fn().mockReturnValue({ properties: { autoStore: true } }),
} as unknown as imperative.ProfileInfo);
const refreshSpy = jest.spyOn(profCache, "refresh").mockImplementation();
await profCache.updateCachedProfile({
...lpar1Profile,
profile: lpar2Profile.profile,
} as imperative.IProfileLoaded);
expect(refreshSpy).toHaveBeenCalledTimes(1);
});

it("updateCachedProfile should update cached profile when autoStore is false", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as imperative.Logger);
profCache.allProfiles = [lpar1Profile as imperative.IProfileLoaded];
(profCache as any).defaultProfileByType = new Map([["zosmf", { ...profCache.allProfiles[0] }]]);
expect(profCache.allProfiles[0].profile).toMatchObject(lpar1Profile.profile);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValueOnce({
getTeamConfig: jest.fn().mockReturnValue({ properties: { autoStore: false } }),
} as unknown as imperative.ProfileInfo);
await profCache.updateCachedProfile({
...lpar1Profile,
profile: lpar2Profile.profile,
} as imperative.IProfileLoaded);
expect(profCache.allProfiles[0].profile).toMatchObject(lpar2Profile.profile);
expect((profCache as any).defaultProfileByType.get("zosmf").profile).toMatchObject(lpar2Profile.profile);
});

it("getDefaultProfile should find default profile given type", () => {
const profCache = new ProfilesCache(fakeLogger as unknown as imperative.Logger);
(profCache as any).defaultProfileByType = new Map([["zosmf", lpar1Profile]]);
@@ -566,18 +597,18 @@ describe("ProfilesCache", () => {
expect(profile).toMatchObject({ name: "lpar1", type: "base" });
});

it("fetchBaseProfile should return typeless profile if base profile does not contain token type", async () => {
it("fetchBaseProfile should return typeless profile if base profile does not contain token value", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as imperative.Logger);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValue(createProfInfoMock([baseProfile]));
const profile = await profCache.fetchBaseProfile("lpar1.zosmf");
expect(profile).toMatchObject({ name: "lpar1", type: "base" });
});

it("fetchBaseProfile should return base profile if it contains token type", async () => {
it("fetchBaseProfile should return base profile if it contains token value", async () => {
const profCache = new ProfilesCache(fakeLogger as unknown as imperative.Logger);
const profInfoMock = createProfInfoMock([baseProfile]);
jest.spyOn(profCache, "getProfileInfo").mockResolvedValue(profInfoMock);
mocked(profInfoMock.getTeamConfig().api.profiles.get).mockReturnValueOnce({ tokenType: imperative.SessConstants.TOKEN_TYPE_JWT });
mocked(profInfoMock.getTeamConfig().api.secure.securePropsForProfile).mockReturnValue(["tokenValue"]);
const profile = await profCache.fetchBaseProfile("lpar1.zosmf");
expect(profile).toMatchObject(baseProfile);
});
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import * as vscode from "vscode";
import { ZoweTreeNode } from "../../../src/tree/ZoweTreeNode";
import { IZoweTreeNode } from "../../../src/tree/IZoweTreeNode";
import * as imperative from "@zowe/imperative";
import { BaseProvider } from "../../../src";

describe("ZoweTreeNode", () => {
const makeNode = (
@@ -79,4 +80,32 @@ describe("ZoweTreeNode", () => {
expect(node.getProfile()).toBeUndefined();
expect(node.getProfileName()).toBeUndefined();
});

it("setProfileToChoice should update properties on existing profile object", () => {
const node = makeNode("test", vscode.TreeItemCollapsibleState.None, undefined, undefined, {
name: "oldProfile",
profile: { host: "example.com" },
});
node.setProfileToChoice({ name: "newProfile", profile: { host: "example.com", port: 443 } } as unknown as imperative.IProfileLoaded);
// Profile name should not change but properties should
expect(node.getProfileName()).toBe("oldProfile");
expect(node.getProfile().profile?.port).toBeDefined();
});

it("setProfileToChoice should update profile for associated FSProvider entry", () => {
const node = makeNode("test", vscode.TreeItemCollapsibleState.None, undefined);
const fsEntry = {
metadata: {
profile: { name: "oldProfile" },
},
};
node.setProfileToChoice(
{ name: "newProfile" } as unknown as imperative.IProfileLoaded,
{
lookup: jest.fn().mockReturnValue(fsEntry),
} as unknown as BaseProvider
);
expect(node.getProfileName()).toBe("newProfile");
expect(fsEntry.metadata.profile.name).toBe("newProfile");
});
});
Original file line number Diff line number Diff line change
@@ -145,6 +145,7 @@ describe("ZoweVsCodeExtension", () => {
mProfileSchemaCache: new Map(),
readProfilesFromDisk: jest.fn(),
});
testCache.allProfiles = [serviceProfile, baseProfile];
jest.spyOn(testCache, "getProfileInfo").mockResolvedValue(testProfInfo);

return {
@@ -338,6 +339,9 @@ describe("ZoweVsCodeExtension", () => {
};

const quickPickMock = jest.spyOn(Gui, "showQuickPick").mockImplementation((items) => items[0]);
await ZoweVsCodeExtension.profilesCache.refresh({
registeredApiTypes: jest.fn().mockReturnValue(["service"]),
} as unknown as Types.IApiRegisterClient);
await ZoweVsCodeExtension.ssoLogin({ serviceProfile: "lpar.service" });

const testSession = new imperative.Session(JSON.parse(JSON.stringify(blockMocks.expectedSession.ISession)));
@@ -541,9 +545,6 @@ describe("ZoweVsCodeExtension", () => {

jest.spyOn(ZoweVsCodeExtension as any, "promptUserPass").mockResolvedValue(["user", "pass"]);
const quickPickMock = jest.spyOn(Gui, "showQuickPick").mockImplementation((items) => items[0]);
await ZoweVsCodeExtension.profilesCache.refresh({
registeredApiTypes: jest.fn().mockReturnValue(["service"]),
} as unknown as Types.IApiRegisterClient);
const didLogin = await ZoweVsCodeExtension.ssoLogin({
serviceProfile: serviceProfileLoaded,
defaultTokenType: "apimlAuthenticationToken",
@@ -633,6 +634,9 @@ describe("ZoweVsCodeExtension", () => {

const testSpy = jest.spyOn(ZoweVsCodeExtension as any, "promptUserPass").mockResolvedValue(["abc", "def"]);
const quickPickMock = jest.spyOn(Gui, "showQuickPick").mockImplementation((items) => items[0]);
await ZoweVsCodeExtension.profilesCache.refresh({
registeredApiTypes: jest.fn().mockReturnValue(["service"]),
} as unknown as Types.IApiRegisterClient);
const didLogin = await ZoweVsCodeExtension.ssoLogin({
serviceProfile: serviceProfileLoaded,
defaultTokenType: "apimlAuthenticationToken",
@@ -686,6 +690,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
const saveCredentialsSpy = jest.spyOn(ZoweVsCodeExtension as any, "saveCredentials");
@@ -711,6 +716,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
const saveCredentialsSpy = jest.spyOn(ZoweVsCodeExtension as any, "saveCredentials");
@@ -739,6 +745,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
jest.spyOn(Gui, "showMessage").mockResolvedValueOnce("yes");
@@ -765,6 +772,7 @@ describe("ZoweVsCodeExtension", () => {
updateProperty: mockUpdateProperty,
}),
refresh: jest.fn(),
updateCachedProfile: jest.fn(),
});
const showInputBoxSpy = jest.spyOn(Gui, "showInputBox").mockResolvedValueOnce("fakeUser").mockResolvedValueOnce("fakePassword");
jest.spyOn(Gui, "showMessage").mockResolvedValueOnce(undefined);
20 changes: 10 additions & 10 deletions packages/zowe-explorer-api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zowe/zowe-explorer-api",
"version": "3.0.0-next-SNAPSHOT",
"version": "3.1.0-SNAPSHOT",
"description": "Extensibility API for Zowe Explorer.",
"publisher": "Zowe",
"author": "Zowe",
@@ -28,15 +28,15 @@
},
"dependencies": {
"@types/vscode": "^1.53.2",
"@zowe/core-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/imperative": "8.0.0-next.202408301809",
"@zowe/secrets-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zos-console-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zos-files-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zos-jobs-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zos-tso-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zos-uss-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/zosmf-for-zowe-sdk": "8.0.0-next.202408301809",
"@zowe/core-for-zowe-sdk": "8.0.0",
"@zowe/imperative": "8.0.0",
"@zowe/secrets-for-zowe-sdk": "8.0.0",
"@zowe/zos-console-for-zowe-sdk": "8.0.0",
"@zowe/zos-files-for-zowe-sdk": "8.0.0",
"@zowe/zos-jobs-for-zowe-sdk": "8.0.0",
"@zowe/zos-tso-for-zowe-sdk": "8.0.0",
"@zowe/zos-uss-for-zowe-sdk": "8.0.0",
"@zowe/zosmf-for-zowe-sdk": "8.0.0",
"deep-object-diff": "^1.1.9",
"mustache": "^4.2.0",
"semver": "^7.6.0"
30 changes: 26 additions & 4 deletions packages/zowe-explorer-api/src/profiles/ProfilesCache.ts
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ import { Validation } from "./Validation";
import { ZosmfProfile } from "@zowe/zosmf-for-zowe-sdk";
import { ZosTsoProfile } from "@zowe/zos-tso-for-zowe-sdk";
import { ZosUssProfile } from "@zowe/zos-uss-for-zowe-sdk";
import { Types } from "../Types";

export class ProfilesCache {
public profilesForValidation: Validation.IValidationProfile[] = [];
@@ -79,9 +80,8 @@ export class ProfilesCache {

/**
* Updates profile in allProfiles array and if default updates defaultProfileByType
*
* @deprecated Use `updateCachedProfile` instead
* @param {string} profileLoaded
*
* @returns {void}
*/
public updateProfilesArrays(profileLoaded: imperative.IProfileLoaded): void {
@@ -97,6 +97,25 @@ export class ProfilesCache {
}
}

public async updateCachedProfile(
profileLoaded: imperative.IProfileLoaded,
profileNode?: Types.IZoweNodeType,
zeRegister?: Types.IApiRegisterClient
): Promise<void> {
if ((await this.getProfileInfo()).getTeamConfig().properties.autoStore) {
await this.refresh(zeRegister);
} else {
// Note: When autoStore is disabled, nested profiles within this service profile may not have their credentials updated.
const profIndex = this.allProfiles.findIndex((profile) => profile.type === profileLoaded.type && profile.name === profileLoaded.name);
this.allProfiles[profIndex].profile = profileLoaded.profile;
const defaultProf = this.defaultProfileByType.get(profileLoaded.type);
if (defaultProf != null && defaultProf.name === profileLoaded.name) {
this.defaultProfileByType.set(profileLoaded.type, profileLoaded);
}
}
profileNode?.setProfileToChoice(profileLoaded);
}

/**
* This returns default profile by type from defaultProfileByType
*
@@ -319,11 +338,14 @@ export class ProfilesCache {
const mProfileInfo = await this.getProfileInfo();
const baseProfileAttrs = mProfileInfo.getDefaultProfile("base");
const config = mProfileInfo.getTeamConfig();
if (profileName?.includes(".") && (baseProfileAttrs == null || config.api.profiles.get(baseProfileAttrs.profName).tokenType == null)) {
if (
profileName?.includes(".") &&
(baseProfileAttrs == null || !config.api.secure.securePropsForProfile(baseProfileAttrs.profName).includes("tokenValue"))
) {
// Retrieve parent typeless profile as base profile if:
// (1) The active profile name is nested (contains a period) AND
// (2) No default base profile was found OR
// Default base profile does not have tokenType defined
// Default base profile does not have tokenValue in secure array
const parentProfile = this.getParentProfileForToken(profileName, config);
return this.getProfileLoaded(parentProfile, "base", config.api.profiles.get(parentProfile));
} else if (baseProfileAttrs == null) {
Loading

0 comments on commit 4466a30

Please sign in to comment.