Skip to content

Commit

Permalink
Merge branch 'main' into fix/update-credentials-desync
Browse files Browse the repository at this point in the history
Signed-off-by: Timothy Johnson <timothy.johnson@broadcom.com>
  • Loading branch information
t1m0thyj authored Sep 25, 2024
2 parents c8ceebf + 3cf3f66 commit 82fa3f7
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 54 deletions.
3 changes: 3 additions & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen

### New features and enhancements

- Users can now follow a prompt to create a new Zowe client configuration. The prompt displays when VS Code is opened with Zowe Explorer installed, but the user does not have any Zowe client configurations. [#3148](https://github.com/zowe/zowe-explorer-vscode/pull/3148)

### Bug fixes

- The "Zowe Resources" panel is now hidden by default until Zowe Explorer reveals it to display a table or other data. [#3113](https://github.com/zowe/zowe-explorer-vscode/issues/3113)
Expand All @@ -16,6 +18,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen
- Fixed an issue where copying and pasting a file/folder in the USS tree would fail abruptly, displaying an error. [#3128](https://github.com/zowe/zowe-explorer-vscode/issues/3128)
- To fix Strange behaviour of Job label under Job Favorites. [#2632](https://github.com/zowe/zowe-explorer-vscode/issues/2632)
- Removal of broken VSC command to `Zowe Explorer: Refresh Zowe Explorer`, use VS Code's `Extensions: Refresh` command instead. [#3100](https://github.com/zowe/zowe-explorer-vscode/issues/3100)
- Fixed issue where Zowe Explorer would reload the VS Code window during initialization when no config files are present. [#3147](https://github.com/zowe/zowe-explorer-vscode/issues/3147)
- Fixed issue where obsolete credentials persisted for PDS member nodes in Data Sets tree. [#3112](https://github.com/zowe/zowe-explorer-vscode/issues/3112)
- Fixed issue where Search operation did not prompt for credentials if profile contains expired token. [#2259](https://github.com/zowe/zowe-explorer-vscode/issues/2259)
- Fixed issue where inactive status was not displayed for profiles loaded from Global Config. [#3134](https://github.com/zowe/zowe-explorer-vscode/issues/3134)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ async function createGlobalMocks() {
getZoweDir: jest.fn(),
};
}),
mockPromptUserWithNoConfigs: jest.fn(),
mockUpdateCredMgrSetting: jest.fn(),
mockWriteOverridesFile: jest.fn(),
mockProfCacheProfileInfo: createInstanceOfProfileInfo(),
Expand Down Expand Up @@ -360,6 +361,10 @@ async function createGlobalMocks() {
get: globalMocks.mockImperativeProfileInfo,
configurable: true,
});
Object.defineProperty(ProfilesUtils, "promptUserWithNoConfigs", {
value: globalMocks.mockPromptUserWithNoConfigs,
configurable: true,
});

// Create a mocked extension context
const mockExtensionCreator = jest.fn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,10 @@ describe("ProfilesUtils unit tests", () => {
inspect: jest.fn(),
update: jest.fn(),
});
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => true,
});
const executeCommandMock = jest.spyOn(vscode.commands, "executeCommand").mockImplementation();
const getValueMock = jest.spyOn(ZoweLocalStorage, "getValue").mockReturnValue(undefined);
const setValueMock = jest.spyOn(ZoweLocalStorage, "setValue").mockImplementation();
Expand All @@ -361,6 +365,42 @@ describe("ProfilesUtils unit tests", () => {
getConfigurationMock.mockRestore();
getValueMock.mockRestore();
setValueMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();

profInfoSpy.mockRestore();
});

it("should not reload the window during migration if imperative.ProfileInfo.onlyV1ProfilesExist is false", async () => {
const profInfoSpy = jest.spyOn(ProfilesUtils, "getProfileInfo").mockReturnValueOnce({
readProfilesFromDisk: jest.fn(),
hasValidSchema: false,
getTeamConfig: () => ({
exists: false,
}),
} as never);
const getConfigurationMock = jest.spyOn(vscode.workspace, "getConfiguration").mockReturnValue({
persistent: true,
get: jest.fn(),
has: jest.fn(),
inspect: jest.fn(),
update: jest.fn(),
});
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => false,
});
const executeCommandMock = jest.spyOn(vscode.commands, "executeCommand").mockImplementation();
const getValueMock = jest.spyOn(ZoweLocalStorage, "getValue").mockReturnValue(undefined);
const setValueMock = jest.spyOn(ZoweLocalStorage, "setValue").mockImplementation();
await ProfilesUtils.readConfigFromDisk(true);
expect(getConfigurationMock).toHaveBeenCalledWith("Zowe-USS-Persistent");
expect(getValueMock).toHaveBeenCalledWith(Definitions.LocalStorageKey.V1_MIGRATION_STATUS);
expect(executeCommandMock).not.toHaveBeenCalledWith("workbench.action.reloadWindow");
executeCommandMock.mockRestore();
getConfigurationMock.mockRestore();
getValueMock.mockRestore();
setValueMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();

profInfoSpy.mockRestore();
});
Expand Down Expand Up @@ -1170,33 +1210,108 @@ describe("ProfilesUtils unit tests", () => {
};
}

it("should return early if the migration status is nullish", () => {
it("should return early if the migration status is nullish", async () => {
const blockMocks = getBlockMocks();
blockMocks.getValueMock.mockReturnValueOnce(undefined);
ProfilesUtils.handleV1MigrationStatus();
await ProfilesUtils.handleV1MigrationStatus();
expect(blockMocks.setValueMock).not.toHaveBeenCalled();
blockMocks.getValueMock.mockRestore();
});

it("should call executeCommand with zowe.ds.addSession if the migration status is CreateConfigSelected", () => {
it("should call executeCommand with zowe.ds.addSession if the migration status is CreateConfigSelected", async () => {
const blockMocks = getBlockMocks();
const executeCommandMock = jest.spyOn(vscode.commands, "executeCommand").mockImplementation();
blockMocks.getValueMock.mockReturnValueOnce(Definitions.V1MigrationStatus.CreateConfigSelected);
blockMocks.setValueMock.mockImplementation();
ProfilesUtils.handleV1MigrationStatus();
await ProfilesUtils.handleV1MigrationStatus();
expect(executeCommandMock.mock.lastCall?.[0]).toBe("zowe.ds.addSession");
blockMocks.getValueMock.mockRestore();
blockMocks.setValueMock.mockRestore();
});

it("should clear the v1 migration status once the migration status is handled", () => {
it("should clear the v1 migration status once the migration status is handled", async () => {
const blockMocks = getBlockMocks();
blockMocks.getValueMock.mockReturnValueOnce(Definitions.V1MigrationStatus.JustMigrated);
blockMocks.setValueMock.mockImplementation();
ProfilesUtils.handleV1MigrationStatus();
expect(blockMocks.setValueMock).toHaveBeenCalledWith(Definitions.LocalStorageKey.V1_MIGRATION_STATUS, undefined);
await ProfilesUtils.handleV1MigrationStatus();
blockMocks.getValueMock.mockRestore();
blockMocks.setValueMock.mockRestore();
});
});

describe("promptUserWithNoConfigs", () => {
it("prompts the user if they don't have any Zowe client configs", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: () => ({ exists: false }),
} as any);
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => false,
});
const showMessageSpy = jest.spyOn(Gui, "showMessage");
await ProfilesUtils.promptUserWithNoConfigs();
expect(showMessageSpy).toHaveBeenCalledWith(
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.",
{ items: ["Create New"] }
);
expect(profInfoMock).toHaveBeenCalled();
profInfoMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();
});
it("executes zowe.ds.addSession if the user selects 'Create New' in the prompt", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: () => ({ exists: false }),
} as any);
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => false,
});
const showMessageSpy = jest.spyOn(Gui, "showMessage").mockResolvedValue("Create New");
const executeCommandMock = jest.spyOn(vscode.commands, "executeCommand").mockImplementation();
await ProfilesUtils.promptUserWithNoConfigs();
expect(showMessageSpy).toHaveBeenCalledWith(
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.",
{ items: ["Create New"] }
);
expect(profInfoMock).toHaveBeenCalled();
expect(executeCommandMock).toHaveBeenCalledWith("zowe.ds.addSession");
executeCommandMock.mockRestore();
profInfoMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();
});
it("does not prompt the user if they have a Zowe team config", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: () => ({ exists: true }),
} as any);
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => false,
});
const showMessageSpy = jest.spyOn(Gui, "showMessage");
await ProfilesUtils.promptUserWithNoConfigs();
expect(showMessageSpy).not.toHaveBeenCalledWith(
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.",
{ items: ["Create New"] }
);
expect(profInfoMock).toHaveBeenCalled();
profInfoMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();
});
it("does not prompt the user if they have v1 profiles", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: () => ({ exists: false }),
} as any);
const onlyV1ProfsExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", {
configurable: true,
get: () => true,
});
const showMessageSpy = jest.spyOn(Gui, "showMessage");
await ProfilesUtils.promptUserWithNoConfigs();
expect(showMessageSpy).not.toHaveBeenCalledWith(
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.",
{ items: ["Create New"] }
);
expect(profInfoMock).toHaveBeenCalled();
profInfoMock.mockRestore();
onlyV1ProfsExistMock[Symbol.dispose]();
});
});
});
55 changes: 28 additions & 27 deletions packages/zowe-explorer/l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"Install": "Install",
"Reload": "Reload",
"No valid schema was found for the active team configuration. This may introduce issues with profiles in Zowe Explorer.": "No valid schema was found for the active team configuration. This may introduce issues with profiles in Zowe Explorer.",
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.": "No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.",
"Create New": "Create New",
"\"Update Credentials\" operation not supported when \"autoStore\" is false": "\"Update Credentials\" operation not supported when \"autoStore\" is false",
"Connection Name": "Connection Name",
"Enter a name for the connection.": "Enter a name for the connection.",
Expand Down Expand Up @@ -85,7 +87,6 @@
},
"Zowe Profiles initialized successfully.": "Zowe Profiles initialized successfully.",
"Convert Existing Profiles": "Convert Existing Profiles",
"Create New": "Create New",
"Operation cancelled": "Operation cancelled",
"Tree Item is not a Zowe Explorer item.": "Tree Item is not a Zowe Explorer item.",
"Zowe Explorer": "Zowe Explorer",
Expand Down Expand Up @@ -170,32 +171,6 @@
"Required API functions for pasting (fileList and copy/uploadFromBuffer) were not found.": "Required API functions for pasting (fileList and copy/uploadFromBuffer) were not found.",
"Uploading USS files...": "Uploading USS files...",
"Error uploading files": "Error uploading files",
"The 'move' function is not implemented for this USS API.": "The 'move' function is not implemented for this USS API.",
"Could not list USS files: Empty path provided in URI": "Could not list USS files: Empty path provided in URI",
"Profile does not exist for this file.": "Profile does not exist for this file.",
"$(sync~spin) Saving USS file...": "$(sync~spin) Saving USS file...",
"Renaming {0} failed due to API error: {1}/File pathError message": {
"message": "Renaming {0} failed due to API error: {1}",
"comment": [
"File path",
"Error message"
]
},
"Deleting {0} failed due to API error: {1}/File nameError message": {
"message": "Deleting {0} failed due to API error: {1}",
"comment": [
"File name",
"Error message"
]
},
"No error details given": "No error details given",
"Error fetching destination {0} for paste action: {1}/USS pathError message": {
"message": "Error fetching destination {0} for paste action: {1}",
"comment": [
"USS path",
"Error message"
]
},
"Downloaded: {0}/Download time": {
"message": "Downloaded: {0}",
"comment": [
Expand Down Expand Up @@ -266,6 +241,32 @@
"initializeUSSFavorites.error.buttonRemove": "initializeUSSFavorites.error.buttonRemove",
"File does not exist. It may have been deleted.": "File does not exist. It may have been deleted.",
"$(sync~spin) Pulling from Mainframe...": "$(sync~spin) Pulling from Mainframe...",
"The 'move' function is not implemented for this USS API.": "The 'move' function is not implemented for this USS API.",
"Could not list USS files: Empty path provided in URI": "Could not list USS files: Empty path provided in URI",
"Profile does not exist for this file.": "Profile does not exist for this file.",
"$(sync~spin) Saving USS file...": "$(sync~spin) Saving USS file...",
"Renaming {0} failed due to API error: {1}/File pathError message": {
"message": "Renaming {0} failed due to API error: {1}",
"comment": [
"File path",
"Error message"
]
},
"Deleting {0} failed due to API error: {1}/File nameError message": {
"message": "Deleting {0} failed due to API error: {1}",
"comment": [
"File name",
"Error message"
]
},
"No error details given": "No error details given",
"Error fetching destination {0} for paste action: {1}/USS pathError message": {
"message": "Error fetching destination {0} for paste action: {1}",
"comment": [
"USS path",
"Error message"
]
},
"{0} location/Node type": {
"message": "{0} location",
"comment": [
Expand Down
19 changes: 10 additions & 9 deletions packages/zowe-explorer/l10n/poeditor.json
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@
"Install": "",
"Reload": "",
"No valid schema was found for the active team configuration. This may introduce issues with profiles in Zowe Explorer.": "",
"No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration.": "",
"Create New": "",
"\"Update Credentials\" operation not supported when \"autoStore\" is false": "",
"Connection Name": "",
"Enter a name for the connection.": "",
Expand All @@ -450,7 +452,6 @@
"Failed to initialize Zowe folder: {0}": "",
"Zowe Profiles initialized successfully.": "",
"Convert Existing Profiles": "",
"Create New": "",
"Operation cancelled": "",
"Tree Item is not a Zowe Explorer item.": "",
"Zowe Explorer": "",
Expand Down Expand Up @@ -490,14 +491,6 @@
"Required API functions for pasting (fileList and copy/uploadFromBuffer) were not found.": "",
"Uploading USS files...": "",
"Error uploading files": "",
"The 'move' function is not implemented for this USS API.": "",
"Could not list USS files: Empty path provided in URI": "",
"Profile does not exist for this file.": "",
"$(sync~spin) Saving USS file...": "",
"Renaming {0} failed due to API error: {1}": "",
"Deleting {0} failed due to API error: {1}": "",
"No error details given": "",
"Error fetching destination {0} for paste action: {1}": "",
"Downloaded: {0}": "",
"Encoding: {0}": "",
"Binary": "",
Expand Down Expand Up @@ -526,6 +519,14 @@
"initializeUSSFavorites.error.buttonRemove": "",
"File does not exist. It may have been deleted.": "",
"$(sync~spin) Pulling from Mainframe...": "",
"The 'move' function is not implemented for this USS API.": "",
"Could not list USS files: Empty path provided in URI": "",
"Profile does not exist for this file.": "",
"$(sync~spin) Saving USS file...": "",
"Renaming {0} failed due to API error: {1}": "",
"Deleting {0} failed due to API error: {1}": "",
"No error details given": "",
"Error fetching destination {0} for paste action: {1}": "",
"{0} location": "",
"Choose a location to create the {0}": "",
"Name of file or directory": "",
Expand Down
4 changes: 2 additions & 2 deletions packages/zowe-explorer/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<ZoweEx
SharedInit.watchConfigProfile(context);
await SharedInit.watchForZoweButtonClick();

ProfilesUtils.handleV1MigrationStatus();

await ProfilesUtils.handleV1MigrationStatus();
await ProfilesUtils.promptUserWithNoConfigs();
return ZoweExplorerApiRegister.getInstance();
}
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/zowe-explorer/src/tools/ZoweLocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export class ZoweLocalStorage {
return ZoweLocalStorage.storage.get<T>(key, defaultValue);
}

public static setValue<T>(key: Definitions.LocalStorageKey | PersistenceSchemaEnum, value: T): void {
public static setValue<T>(key: Definitions.LocalStorageKey | PersistenceSchemaEnum, value: T): Thenable<void> {
ZoweLogger.trace("ZoweLocalStorage.setValue called.");
ZoweLocalStorage.storage.update(key, value);
return ZoweLocalStorage.storage.update(key, value);
}
}
Loading

0 comments on commit 82fa3f7

Please sign in to comment.