Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profile management #2472

Merged
merged 41 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ea8fd30
initial work for profile management
JillieBeanSim Sep 21, 2023
82c1974
add token auth part
JillieBeanSim Sep 21, 2023
723e375
remove other commands similar to new profile management options
JillieBeanSim Sep 21, 2023
041bd1f
add commands back without when clause as to not be breaking change
JillieBeanSim Sep 21, 2023
7c49e51
run localization scripts
JillieBeanSim Sep 21, 2023
36e3120
add items back to package.nls.json
JillieBeanSim Sep 21, 2023
f6010fc
realign for easier comparison
JillieBeanSim Sep 21, 2023
d6346a7
handle case of no authentication method shown for profile
JillieBeanSim Sep 21, 2023
84cf3b5
add changelog
JillieBeanSim Sep 21, 2023
fb680bb
update strings in different scenarios
JillieBeanSim Sep 22, 2023
6a4d068
separate the work
JillieBeanSim Sep 22, 2023
61a021a
update check and strings in Profiles.ssoLogin
JillieBeanSim Sep 22, 2023
0245bb7
clean up and add some unit tests
JillieBeanSim Sep 22, 2023
3444400
fix qp labels I broke
JillieBeanSim Sep 22, 2023
b5139a5
add unit tests
JillieBeanSim Sep 22, 2023
29987e6
cut down on duplication of test code
JillieBeanSim Sep 22, 2023
4484235
clear more duplication
JillieBeanSim Sep 22, 2023
8479821
cleanup
JillieBeanSim Sep 22, 2023
c046daa
clean duplication unit testing
JillieBeanSim Sep 22, 2023
4d4637c
this should fix high duplication failure
JillieBeanSim Sep 22, 2023
c22dbc2
don't think I can condense anything else from file
JillieBeanSim Sep 22, 2023
39194d0
add delete to management options and group left profile items
JillieBeanSim Sep 22, 2023
8daf411
should fix theia tests for delete
JillieBeanSim Sep 23, 2023
6d491d8
about as clean as test file can get
JillieBeanSim Sep 23, 2023
eaeec46
add message for manual editing with opening of config
JillieBeanSim Sep 23, 2023
7ff9223
missed one
JillieBeanSim Sep 23, 2023
b9cd91c
address feedback
JillieBeanSim Sep 26, 2023
2c5eba7
fix unit tests
JillieBeanSim Sep 26, 2023
6006d3c
address feedback
JillieBeanSim Sep 27, 2023
3990e7a
Merge remote-tracking branch 'origin/main' into profile-management
JillieBeanSim Sep 27, 2023
5b57f4c
update log string
JillieBeanSim Sep 27, 2023
c5dd06c
address code smell
JillieBeanSim Sep 27, 2023
af7e90c
Merge branch 'main' into profile-management
JillieBeanSim Sep 28, 2023
fdace6e
address login feedback
JillieBeanSim Oct 2, 2023
71cd777
move enable, disable, and delete to quickpick
JillieBeanSim Oct 2, 2023
f4b0e0c
Merge branch 'main' into profile-management
JillieBeanSim Oct 2, 2023
ccc9223
Merge branch 'main' into profile-management
JillieBeanSim Oct 2, 2023
00af763
add unit tests
JillieBeanSim Oct 2, 2023
742a90e
address feedback
JillieBeanSim Oct 6, 2023
b55efdc
Merge branch 'main' into profile-management
JillieBeanSim Oct 9, 2023
60e3c9d
Merge branch 'main' into profile-management
JillieBeanSim Oct 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen
### New features and enhancements

- Added "Sort Jobs" feature for job nodes in Jobs tree view. [#2257](https://github.com/zowe/vscode-extension-for-zowe/issues/2251)
- Introduce a new user interface for managing profiles via right-click action "Manage Profile".

### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,7 @@ describe("Profiles Unit Tests - function checkCurrentProfile", () => {
it("should throw an error if using token auth and is logged out or has expired token", async () => {
const globalMocks = await createGlobalMocks();
jest.spyOn(utils, "errorHandling").mockImplementation();
jest.spyOn(utils, "isUsingTokenAuth").mockResolvedValue(true);
jest.spyOn(utils.ProfilesUtils, "isUsingTokenAuth").mockResolvedValue(true);
setupProfilesCheck(globalMocks);
await expect(Profiles.getInstance().checkCurrentProfile(globalMocks.testProfile)).resolves.toEqual({ name: "sestest", status: "unverified" });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ async function createGlobalMocks() {
"zowe.manualPoll",
"zowe.updateSecureCredentials",
"zowe.promptCredentials",
"zowe.profileManagement",
"zowe.openRecentMember",
"zowe.searchInAllLoadedItems",
"zowe.ds.deleteProfile",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* 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 { ZoweDatasetNode } from "../../../src/dataset/ZoweDatasetNode";
import * as sharedMock from "../../../__mocks__/mockCreators/shared";
import * as dsMock from "../../../__mocks__/mockCreators/datasets";
import * as profUtils from "../../../src/utils/ProfilesUtils";
import { ProfileManagement } from "../../../src/utils/ProfileManagement";
import { Gui } from "@zowe/zowe-explorer-api";
import { ZoweLogger } from "../../../src/utils/LoggerUtils";

jest.mock("fs");
jest.mock("vscode");
jest.mock("@zowe/cli");

describe("ProfileManagement unit tests", () => {
afterEach(() => {
jest.clearAllMocks();
});
function createGlobalMocks() {
const newMocks = {
mockSession: sharedMock.createISession(),
mockBasicAuthProfile: sharedMock.createValidIProfile(),
mockDsSessionNode: ZoweDatasetNode,
mockUpdateChosen: null as any,
mockAddBasicChosen: null as any,
mockLoginChosen: null as any,
mockLogoutChosen: null as any,
mockEditProfChosen: null as any,
mockCreateQp: jest.fn(),
debugLogSpy: null as any,
};
newMocks.mockDsSessionNode = dsMock.createDatasetSessionNode(newMocks.mockSession, newMocks.mockBasicAuthProfile) as any;
Object.defineProperty(newMocks.mockDsSessionNode, "getProfile", {
value: jest.fn().mockReturnValue(newMocks.mockBasicAuthProfile),
configurable: true,
});
newMocks.mockUpdateChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.update];
newMocks.mockAddBasicChosen = ProfileManagement.basicAuthQpItems[ProfileManagement.AuthQpLabels.add];
newMocks.mockLoginChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.login];
newMocks.mockLogoutChosen = ProfileManagement.tokenAuthQpItems[ProfileManagement.AuthQpLabels.logout];
newMocks.mockEditProfChosen = ProfileManagement.otherProfileQpItems[ProfileManagement.AuthQpLabels.edit];
newMocks.mockCreateQp.mockReturnValue({
show: jest.fn(() => {
return {};
}),
hide: jest.fn(() => {
return {};
}),
onDidAccept: jest.fn(() => {
return {};
}),
});
Object.defineProperty(profUtils.ProfilesUtils, "promptCredentials", { value: jest.fn(), configurable: true });
Object.defineProperty(Gui, "createQuickPick", { value: jest.fn(), configurable: true });
Object.defineProperty(Gui, "createQuickPick", { value: newMocks.mockCreateQp, configurable: true });
Object.defineProperty(ZoweLogger, "debug", { value: jest.fn(), configurable: true });
newMocks.debugLogSpy = jest.spyOn(ZoweLogger, "debug");
// Object.defineProperty(profUtils.ProfilesUtils, "isUsingTokenAuth", { value: jest.fn().mockResolvedValueOnce(false), configurable: true });

return newMocks;
}
afterEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
});
it("profile using basic authentication should see Operation Cancelled when escaping quick pick", async () => {
const globalMocks = createGlobalMocks();
const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`;
Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(undefined), configurable: true });
const updateSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials");
const opCancelledSpy = jest.spyOn(Gui, "infoMessage");
await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any);
expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg);
expect(updateSpy).not.toBeCalled();
expect(opCancelledSpy).toBeCalledWith("Operation Cancelled");
globalMocks.debugLogSpy.mockClear();
updateSpy.mockClear();
opCancelledSpy.mockClear();
});
it("profile using basic authentication should see promptCredentials called when Update Credentials chosen", async () => {
const globalMocks = createGlobalMocks();
const logMsg = `Profile ${globalMocks.mockBasicAuthProfile.name} is using basic authentication.`;
Object.defineProperty(Gui, "resolveQuickPick", { value: jest.fn().mockResolvedValueOnce(globalMocks.mockUpdateChosen), configurable: true });
const scenarioSpy = jest.spyOn(profUtils.ProfilesUtils, "promptCredentials");
await ProfileManagement.manageProfile(globalMocks.mockDsSessionNode as any);
expect(globalMocks.debugLogSpy).toBeCalledWith(logMsg);
expect(scenarioSpy).toBeCalled();
globalMocks.debugLogSpy.mockClear();
scenarioSpy.mockClear();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ describe("ProfilesUtils unit tests", () => {
jest.spyOn(Profiles.getInstance(), "getDefaultProfile").mockReturnValueOnce({} as any);
jest.spyOn(Profiles.getInstance(), "getLoadedProfConfig").mockResolvedValue({ type: "test" } as any);
jest.spyOn(Profiles.getInstance(), "getSecurePropsForProfile").mockResolvedValue([]);
await expect(profUtils.isUsingTokenAuth("test")).resolves.toEqual(false);
await expect(profUtils.ProfilesUtils.isUsingTokenAuth("test")).resolves.toEqual(false);
});
});
});
6 changes: 5 additions & 1 deletion packages/zowe-explorer/i18n/sample/package.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs",
"viewsContainers.activitybar": "Zowe Explorer",
"zowe.promptCredentials": "Update Credentials",
"zowe.profileManagement": "Manage Profile",
"zowe.extRefresh": "Refresh Zowe Explorer",
"zowe.ds.explorer": "Data Sets",
"zowe.uss.explorer": "Unix System Services (USS)",
Expand Down Expand Up @@ -146,5 +147,8 @@
"createZoweSchema.reload.button": "Reload Window",
"createZoweSchema.reload.infoMessage": "Team Configuration file created. Location: {0}. \n Please reload your window.",
"copyFile": "Copy",
"pasteFile": "Paste"
"pasteFile": "Paste",
"jobs.sortbyreturncode": "Sort by ReturnCode",
"jobs.sortbyname": "Sort by Name",
"jobs.sortbyid": "Sort by ID"
}
3 changes: 2 additions & 1 deletion packages/zowe-explorer/i18n/sample/src/Profiles.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"validateProfiles.progress": "Validating {0} Profile.",
"validateProfiles.cancelled": "Validating {0} was cancelled.",
"validateProfiles.error": "Profile validation failed for {0}.",
"ssoAuth.noBase": "This profile does not support token authentication.",
"ssoAuth.usingBasicAuth": "This profile is using basic authentication and does not support token authentication.",
"ssoLogin.tokenType.error": "Error getting supported tokenType value for profile {0}",
"ssoLogin.successful": "Login to authentication service was successful.",
"ssoLogin.error": "Unable to log in with {0}. {1}",
"ssoLogout.successful": "Logout from authentication service was successful for {0}.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"profiles.operation.cancelled": "Operation Cancelled",
"qpPlaceholders.qp.basic": "Profile {0} is using basic authentication. Choose a profile action.",
"qpPlaceholders.qp.token": "Profile {0} is using token authentication. Choose a profile action.",
"qpPlaceholders.qp.choose": "Profile {0} doesn't specify an authentication method. Choose a profile action.",
"addBasicAuthQpItem.addCredentials.qpLabel": "$(plus) Add Credentials",
"addBasicAuthQpItem.addCredentials.qpDetail": "Add username and password for basic authentication",
"updateBasicAuthQpItem.updateCredentials.qpLabel": "$(refresh) Update Credentials",
"updateBasicAuthQpItem.updateCredentials.qpDetail": "Update stored username and password",
"editProfileQpItem.editProfile.qpLabel": "$(pencil) Edit profile",
"editProfileQpItem.editProfile.qpDetail": "Update profile connection information",
"loginQpItem.login.qpLabel": "$(arrow-right) Log in to authentication service",
"loginQpItem.login.qpDetail": "Log in to obtain a new token value",
"logoutQpItem.logout.qpLabel": "$(arrow-left) Log out of authentication service",
"logoutQpItem.logout.qpDetail": "Log out to invalidate and remove stored token value"
}
66 changes: 15 additions & 51 deletions packages/zowe-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@
"title": "%zowe.promptCredentials%",
"category": "Zowe Explorer"
},
{
"command": "zowe.profileManagement",
"title": "%zowe.profileManagement%",
"category": "Zowe Explorer"
},
{
"command": "zowe.extRefresh",
"title": "%zowe.extRefresh%",
Expand Down Expand Up @@ -965,23 +970,8 @@
},
{
"when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection",
"command": "zowe.promptCredentials",
"group": "098_zowe_ussProfileAuthentication@3"
},
{
"when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection",
"command": "zowe.uss.ssoLogin",
"group": "098_zowe_ussProfileAuthentication@4"
},
{
"when": "view == zowe.uss.explorer && viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection",
"command": "zowe.uss.ssoLogout",
"group": "098_zowe_ussProfileAuthentication@5"
},
{
"when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/ && !listMultiSelection",
"command": "zowe.uss.editSession",
"group": "099_zowe_ussProfileModification@1"
"command": "zowe.profileManagement",
"group": "099_zowe_ussProfileAuthentication@97"
},
{
"when": "viewItem =~ /^(?!.*_fav.*)ussSession.*/",
Expand Down Expand Up @@ -1180,23 +1170,8 @@
},
{
"when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection",
"command": "zowe.promptCredentials",
"group": "098_zowe_dsProfileAuthentication@8"
},
{
"when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection",
"command": "zowe.ds.ssoLogin",
"group": "098_zowe_dsProfileAuthentication@9"
},
{
"when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection",
"command": "zowe.ds.ssoLogout",
"group": "098_zowe_dsProfileAuthentication@10"
},
{
"when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/ && !listMultiSelection",
"command": "zowe.ds.editSession",
"group": "099_zowe_dsProfileModification@0"
"command": "zowe.profileManagement",
"group": "099_zowe_dsProfileAuthentication@97"
},
{
"when": "view == zowe.ds.explorer && viewItem =~ /^(?!.*_fav.*)session.*/",
Expand Down Expand Up @@ -1345,23 +1320,8 @@
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.promptCredentials",
"group": "098_zowe_jobsProfileAuthentication@5"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.ssoLogin",
"group": "098_zowe_jobsProfileAuthentication@6"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.ssoLogout",
"group": "098_zowe_jobsProfileAuthentication@7"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/ && !listMultiSelection",
"command": "zowe.jobs.editSession",
"group": "099_zowe_jobsProfileModification@0"
"command": "zowe.profileManagement",
"group": "098_zowe_jobsProfileAuthentication@97"
},
{
"when": "view == zowe.jobs.explorer && viewItem =~ /^(?!.*_fav.*)server.*/",
Expand Down Expand Up @@ -1729,6 +1689,10 @@
{
"command": "zowe.jobs.deleteJob",
"when": "never"
},
{
"command": "zowe.profileManagement",
"when": "never"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions packages/zowe-explorer/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "VS Code extension, powered by Zowe CLI, that streamlines interaction with mainframe data sets, USS files, and jobs",
"viewsContainers.activitybar": "Zowe Explorer",
"zowe.promptCredentials": "Update Credentials",
"zowe.profileManagement": "Manage Profile",
"zowe.extRefresh": "Refresh Zowe Explorer",
"zowe.ds.explorer": "Data Sets",
"zowe.uss.explorer": "Unix System Services (USS)",
Expand Down
18 changes: 11 additions & 7 deletions packages/zowe-explorer/src/Profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import {
getFullPath,
getZoweDir,
} from "@zowe/zowe-explorer-api";
import { errorHandling, FilterDescriptor, FilterItem, ProfilesUtils, isUsingTokenAuth } from "./utils/ProfilesUtils";
import { errorHandling, FilterDescriptor, FilterItem, ProfilesUtils } from "./utils/ProfilesUtils";
import { ZoweExplorerApiRegister } from "./ZoweExplorerApiRegister";
import { ZoweExplorerExtender } from "./ZoweExplorerExtender";
import * as globals from "./globals";
Expand Down Expand Up @@ -88,7 +88,7 @@ export class Profiles extends ProfilesCache {
public async checkCurrentProfile(theProfile: zowe.imperative.IProfileLoaded): Promise<IProfileValidation> {
ZoweLogger.trace("Profiles.checkCurrentProfile called.");
let profileStatus: IProfileValidation;
const usingTokenAuth = await isUsingTokenAuth(theProfile.name);
const usingTokenAuth = await ProfilesUtils.isUsingTokenAuth(theProfile.name);

if (usingTokenAuth && !theProfile.profile.tokenType) {
const error = new zowe.imperative.ImperativeError({
Expand Down Expand Up @@ -1165,16 +1165,18 @@ export class Profiles extends ProfilesCache {
serviceProfile = this.loadNamedProfile(label.trim());
}
// This check will handle service profiles that have username and password
if (serviceProfile.profile.user && serviceProfile.profile.password) {
Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication."));
if (ProfilesUtils.isProfileUsingBasicAuth(serviceProfile)) {
Gui.showMessage(
localize("ssoAuth.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.")
);
return;
}

try {
loginTokenType = await ZoweExplorerApiRegister.getInstance().getCommonApi(serviceProfile).getTokenTypeName();
} catch (error) {
ZoweLogger.warn(error);
Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication."));
Gui.showMessage(localize("ssoLogin.tokenType.error", "Error getting supported tokenType value for profile {0}", serviceProfile.name));
return;
}
try {
Expand All @@ -1196,8 +1198,10 @@ export class Profiles extends ProfilesCache {
ZoweLogger.trace("Profiles.ssoLogout called.");
const serviceProfile = node.getProfile();
// This check will handle service profiles that have username and password
if (serviceProfile.profile?.user && serviceProfile.profile?.password) {
Gui.showMessage(localize("ssoAuth.noBase", "This profile does not support token authentication."));
if (ProfilesUtils.isProfileUsingBasicAuth(serviceProfile)) {
Gui.showMessage(
localize("ssoAuth.usingBasicAuth", "This profile is using basic authentication and does not support token authentication.")
);
return;
}
try {
Expand Down
2 changes: 1 addition & 1 deletion packages/zowe-explorer/src/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export let DS_DIR: string;
export let CONFIG_PATH; // set during activate
export let ISTHEIA = false; // set during activate
export let LOG: imperative.Logger;
export const COMMAND_COUNT = 113;
export const COMMAND_COUNT = 114;
export const MAX_SEARCH_HISTORY = 5;
export const MAX_FILE_HISTORY = 10;
export const MS_PER_SEC = 1000;
Expand Down
7 changes: 7 additions & 0 deletions packages/zowe-explorer/src/shared/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { ZoweLogger } from "../utils/LoggerUtils";
import { ZoweSaveQueue } from "../abstract/ZoweSaveQueue";
import { SettingsConfig } from "../utils/SettingsConfig";
import { spoolFilePollEvent } from "../job/actions";
import { ProfileManagement } from "../utils/ProfileManagement";

// Set up localization
nls.config({
Expand Down Expand Up @@ -92,6 +93,12 @@ export function registerCommonCommands(context: vscode.ExtensionContext, provide
})
);

context.subscriptions.push(
vscode.commands.registerCommand("zowe.profileManagement", async (node: IZoweTreeNode) => {
await ProfileManagement.manageProfile(node);
})
);

// Register functions & event listeners
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(async (e) => {
Expand Down
Loading