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

2128/confirm prompt validator not invoked as expected #2378

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c0040fc
fix(abap-deploy-config-inquirer ): handle confirm validator not being…
longieirl Sep 17, 2024
5685393
fix(abap-deploy-config-inquirer ): add changeset
longieirl Sep 17, 2024
0fdd6b4
fix(abap-deploy-config-inquirer ): fix tests
longieirl Sep 17, 2024
0e0aa15
fix(abap-deploy-config-inquirer ): further cleanup based on testing
longieirl Sep 17, 2024
b244201
fix(abap-deploy-config-inquirer ): add more tests around scp setter m…
longieirl Sep 17, 2024
49a1a51
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 18, 2024
f78448c
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 20, 2024
2dade8e
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 20, 2024
c6b5891
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 24, 2024
910f79e
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 25, 2024
4cebdab
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Sep 30, 2024
cbabfa5
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 1, 2024
44fa530
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 2, 2024
e6a743d
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 2, 2024
64c1d6a
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 4, 2024
7a4b6a9
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 7, 2024
332cc79
fix(abap-deploy-config-inquirer ): add comment
longieirl Oct 7, 2024
54a7caa
Merge branch 'main' of github.com:SAP/open-ux-tools into 2128/confirm…
longieirl Oct 7, 2024
461741d
fix(abap-deploy-config-inquirer ): add more robust test
longieirl Oct 7, 2024
864a295
fix(abap-deploy-config-inquirer ): address sonar issue
longieirl Oct 7, 2024
55782f8
fix(abap-deploy-config-inquirer ): address sonar issue
longieirl Oct 8, 2024
4aa1406
fix(abap-deploy-config-inquirer ): address sonar issue
longieirl Oct 8, 2024
025b4b2
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 9, 2024
aa433e9
fix(abap-deploy-config-inquirer ): fix merge conflicts
longieirl Oct 14, 2024
3df07ed
Merge branch 'main' into 2128/confirm-validator-not-invoked
longieirl Oct 16, 2024
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
5 changes: 5 additions & 0 deletions .changeset/thick-owls-collect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sap-ux/abap-deploy-config-inquirer': patch
---

Handle validator method not being invoked for confirm field
42 changes: 17 additions & 25 deletions packages/abap-deploy-config-inquirer/src/prompts/conditions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { isAppStudio } from '@sap-ux/btp-utils';
import { PromptState } from './prompt-state';
import { clientDoesNotExistOrInvalid } from '../validator-utils';
import { findBackendSystemByUrl, initTransportConfig } from '../utils';
import { handleTransportConfigError } from '../error-handler';
import { t } from '../i18n';
Expand Down Expand Up @@ -53,52 +52,45 @@ export function showScpQuestion(previousAnswers: AbapDeployConfigAnswersInternal
}

/**
* Client condition to determine if the client question should be shown.
* Client condition to determine if the client question should be shown. Validates the SCP confirmation and project configuration properties.
*
* @param isS4HanaCloudSystem - is S/4 HANA Cloud system
* @param scp - is SCP system
* @returns boolean
*/
function showClientCondition(isS4HanaCloudSystem?: boolean): boolean {
function showClientCondition(scp?: boolean): boolean {
IainSAP marked this conversation as resolved.
Show resolved Hide resolved
return Boolean(
!isAppStudio() &&
clientDoesNotExistOrInvalid(PromptState.abapDeployConfig.client) &&
!PromptState.abapDeployConfig.scp &&
!isS4HanaCloudSystem
!isAppStudio() && !PromptState.abapDeployConfig?.isS4HC && !scp && !PromptState.abapDeployConfig?.scp
);
}

/**
* Determines if the client choice question should be shown.
*
* @param previousAnswers - previous answers
* @param client - client
* @param isS4HanaCloudSystem - is S/4 HANA Cloud system
* @returns boolean
*/
export function showClientChoiceQuestion(client?: string, isS4HanaCloudSystem?: boolean): boolean {
export function showClientChoiceQuestion(previousAnswers?: AbapDeployConfigAnswersInternal, client?: string): boolean {
if (PromptState.isYUI || !client) {
return false;
}

return showClientCondition(isS4HanaCloudSystem);
return showClientCondition(previousAnswers?.scp) && previousAnswers?.targetSystem === TargetSystemType.Url;
}

/**
* Determines if the client question should be shown.
* Note: In some instances, when a yaml conf is parsed, double quoted properties i.e. client: "100" are saved as a number instead of a string.
* Determines if the client question should be shown under very specific conditions.
*
* @param clientChoice - client choice from previous answers
* @param client - client
* @param isS4HanaCloudSystem - is S/4 HANA Cloud system
* @param previousAnswers - previous answers
* @returns boolean
*/
export function showClientQuestion(clientChoice?: string, client?: string, isS4HanaCloudSystem?: boolean): boolean {
const clientCondition = showClientCondition(isS4HanaCloudSystem);

if (clientCondition && client) {
PromptState.abapDeployConfig.client = String(client);
}
const showOnCli = clientChoice === ClientChoiceValue.New || !client;
return !PromptState.isYUI ? showOnCli && clientCondition : clientCondition;
export function showClientQuestion(previousAnswers?: AbapDeployConfigAnswersInternal): boolean {
const clientCondition = showClientCondition(previousAnswers?.scp);
const isTargetUrl = previousAnswers?.targetSystem === TargetSystemType.Url;
const showCli = !PromptState.isYUI
? previousAnswers?.clientChoice === ClientChoiceValue.New || isTargetUrl
: isTargetUrl;
const showYui = PromptState.isYUI ? isTargetUrl : false;
return (showYui && clientCondition) || (showCli && clientCondition);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
validateClientChoiceQuestion,
validateClient,
validateDestinationQuestion,
validateScpQuestion,
validateTargetSystem,
validateTargetSystemUrlCli,
validateUrl,
Expand All @@ -26,6 +25,7 @@ import {
} from '../../types';
import type { InputQuestion, ListQuestion, ConfirmQuestion, YUIQuestion } from '@sap-ux/inquirer-common';
import type { Question } from 'inquirer';
import { TargetSystemType } from '../../types';

/**
* Returns the destination prompt.
Expand Down Expand Up @@ -158,18 +158,31 @@ function getUrlPrompt(
* @param backendTarget - backend target
* @returns confirm question for scp
*/
function getScpPrompt(backendTarget?: BackendTarget): Question<AbapDeployConfigAnswersInternal> {
return {
when: (previousAnswers: AbapDeployConfigAnswersInternal): boolean => showScpQuestion(previousAnswers),
type: 'confirm',
name: promptNames.scp,
message: t('prompts.target.scp.message'),
guiOptions: {
breadcrumb: t('prompts.target.scp.breadcrumb')
function getScpPrompt(backendTarget?: BackendTarget): Question<AbapDeployConfigAnswersInternal>[] {
const prompts: (ConfirmQuestion<AbapDeployConfigAnswersInternal> | Question)[] = [
{
when: (previousAnswers: AbapDeployConfigAnswersInternal): boolean => showScpQuestion(previousAnswers),
type: 'confirm',
name: promptNames.scp,
message: t('prompts.target.scp.message'),
guiOptions: {
breadcrumb: t('prompts.target.scp.breadcrumb')
},
default: (): boolean | undefined => backendTarget?.abapTarget?.scp
}
];
// Setter prompt to ensure the state for both CLI and YUI is updated
prompts.push({
when: (answers: AbapDeployConfigAnswersInternal): boolean => {
const scpChoice = answers[promptNames.scp];
const targetChoice = answers[promptNames.targetSystem];
// scpChoice by default is true so only update state if target system is a URL
PromptState.abapDeployConfig.scp = !!(targetChoice === TargetSystemType.Url && scpChoice);
return false;
},
default: (): boolean | undefined => backendTarget?.abapTarget?.scp,
validate: (scp: boolean): boolean | string => validateScpQuestion(scp)
} as ConfirmQuestion<AbapDeployConfigAnswersInternal>;
name: promptNames.scpSetter
} as Question);
return prompts;
}

/**
Expand All @@ -183,8 +196,8 @@ function getClientChoicePrompt(
): (YUIQuestion<AbapDeployConfigAnswersInternal> | Question)[] {
const prompts: (ListQuestion<AbapDeployConfigAnswersInternal> | Question)[] = [
{
when: (): boolean =>
showClientChoiceQuestion(backendTarget?.abapTarget?.client, PromptState.abapDeployConfig?.isS4HC),
when: (previousAnswers: AbapDeployConfigAnswersInternal): boolean =>
showClientChoiceQuestion(previousAnswers, backendTarget?.abapTarget?.client),
type: 'list',
name: promptNames.clientChoice,
message: t('prompts.target.clientChoice.message'),
Expand Down Expand Up @@ -217,25 +230,20 @@ function getClientChoicePrompt(
/**
* Returns the client prompt.
*
* @param backendTarget - backend target
* @returns input question for client
*/
function getClientPrompt(backendTarget?: BackendTarget): Question<AbapDeployConfigAnswersInternal> {
function getClientPrompt(): Question<AbapDeployConfigAnswersInternal> {
return {
when: (previousAnswers: AbapDeployConfigAnswersInternal): boolean => {
return showClientQuestion(
previousAnswers.clientChoice,
backendTarget?.abapTarget?.client,
PromptState.abapDeployConfig?.isS4HC
);
return showClientQuestion(previousAnswers);
},
type: 'input',
name: promptNames.client,
message: t('prompts.target.client.message'),
guiOptions: {
breadcrumb: t('prompts.target.client.breadcrumb')
},
default: (): string | undefined => backendTarget?.abapTarget?.client,
default: (): string | undefined => PromptState.abapDeployConfig?.client, // Already set from previous step, if passed in from yaml config for example
filter: (input: string): string => input?.trim(),
validate: (client: string): boolean | string => validateClient(client)
} as InputQuestion<AbapDeployConfigAnswersInternal>;
Expand All @@ -256,8 +264,8 @@ export async function getAbapTargetPrompts(
...getDestinationPrompt(abapSystemChoices, destinations, options.backendTarget),
...getTargetSystemPrompt(abapSystemChoices),
getUrlPrompt(destinations, options.backendTarget),
getScpPrompt(options.backendTarget),
...getScpPrompt(options.backendTarget),
...getClientChoicePrompt(options.backendTarget),
getClientPrompt(options.backendTarget)
getClientPrompt()
];
}
11 changes: 0 additions & 11 deletions packages/abap-deploy-config-inquirer/src/prompts/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,17 +158,6 @@ export function validateTargetSystemUrlCli(targetSystem?: string, choices?: Abap
}
}

/**
* Validates the SCP question and sets the SCP in the prompt state.
*
* @param input - if confirm was selected
* @returns boolean
*/
export function validateScpQuestion(input: boolean): boolean {
PromptState.abapDeployConfig.scp = input;
return true;
}

/**
* Validates and updates the client property in the state.
*
Expand Down
1 change: 1 addition & 0 deletions packages/abap-deploy-config-inquirer/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export enum promptNames {
targetSystemCliSetter = 'targetSystemCliSetter',
url = 'url',
scp = 'scp',
scpSetter = 'scpSetter',
clientChoice = 'clientChoice',
clientChoiceCliSetter = 'clientChoiceCliSetter',
client = 'client',
Expand Down
10 changes: 0 additions & 10 deletions packages/abap-deploy-config-inquirer/src/validator-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,6 @@ export function isValidClient(client: string): boolean {
return !!regex.exec(client);
}

/**
* Returns true if the input does not exist, or if it exists but it is invalid.
*
* @param client - input string
* @returns boolean
*/
export function clientDoesNotExistOrInvalid(client?: string): boolean {
return Boolean(!client || (client && !isValidClient(client)));
}

/**
* Returns the list of packages for the given input.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/abap-deploy-config-inquirer/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('index', () => {
});
const prompts = await getPrompts({}, undefined, false);
expect(prompts.answers).toBeDefined();
expect(prompts.prompts.length).toBe(23);
expect(prompts.prompts.length).toBe(24);
});

it('should prompt with inquirer adapter', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { isAppStudio } from '@sap-ux/btp-utils';
import { ClientChoiceValue, PackageInputChoices, TransportChoices, TransportConfig } from '../../src/types';
import {
ClientChoiceValue,
PackageInputChoices,
TargetSystemType,
TransportChoices,
TransportConfig
} from '../../src/types';
import {
defaultOrShowManualPackageQuestion,
defaultOrShowManualTransportQuestion,
Expand Down Expand Up @@ -70,25 +76,93 @@ describe('Test abap deploy config inquirer conditions', () => {
test('should show client choice question', () => {
mockIsAppStudio.mockReturnValueOnce(false);
PromptState.isYUI = false;
expect(showClientChoiceQuestion('100', false)).toBe(true);
PromptState.abapDeployConfig.isS4HC = false;
expect(
showClientChoiceQuestion({ scp: false, targetSystem: TargetSystemType.Url, url: '', package: '' }, '100')
).toBe(true);
PromptState.resetAbapDeployConfig();
// Should not show client choice question if SCP is enabled
PromptState.abapDeployConfig.isS4HC = false;
PromptState.abapDeployConfig.scp = true;
expect(
showClientChoiceQuestion({ scp: false, targetSystem: TargetSystemType.Url, url: '', package: '' }, '100')
).toBe(false);
PromptState.resetAbapDeployConfig();
// Should not show client choice question if target system is not a URL
PromptState.abapDeployConfig.isS4HC = false;
PromptState.abapDeployConfig.scp = true;
expect(showClientChoiceQuestion({ scp: true, url: '', package: '' }, '100')).toBe(false);
PromptState.resetAbapDeployConfig();
});

test('should not show client choice question', () => {
mockIsAppStudio.mockReturnValueOnce(false);
PromptState.isYUI = false;
expect(showClientChoiceQuestion(undefined, true)).toBe(false);
PromptState.abapDeployConfig.isS4HC = true;
expect(
showClientChoiceQuestion({ scp: true, targetSystem: TargetSystemType.Url, url: '', package: '' }, undefined)
).toBe(false);
PromptState.resetAbapDeployConfig();
});

test('should show client question', () => {
PromptState.isYUI = true;
mockIsAppStudio.mockReturnValueOnce(false);
expect(showClientQuestion(undefined, undefined, false)).toBe(true);
});
it.each([
{ isYui: true, scpEnabled: false, scpDisabled: true, clientChoice: undefined },
{
isYui: false,
scpEnabled: false,
scpDisabled: true,
clientChoice: ClientChoiceValue.New
},
{ isYui: false, scpEnabled: false, scpDisabled: true, clientChoice: undefined }
])(
'Validate showClientQuestion for different environments isYui: $isYui, clientChoice: $clientChoice',
({ isYui, scpEnabled, scpDisabled, clientChoice }) => {
PromptState.resetAbapDeployConfig();
PromptState.isYUI = isYui;
mockIsAppStudio.mockReturnValueOnce(false);
// Validate client question if SCP is enabled
PromptState.abapDeployConfig.isS4HC = false;
expect(showClientQuestion({ scp: true, targetSystem: TargetSystemType.Url, url: '', package: '' })).toBe(
scpEnabled
);
PromptState.resetAbapDeployConfig();
// Validate client question if SCP is disabled
PromptState.abapDeployConfig.client = '100';
PromptState.abapDeployConfig.isS4HC = false;
expect(
showClientQuestion({
scp: false,
clientChoice,
targetSystem: TargetSystemType.Url,
url: '',
package: ''
})
).toBe(scpDisabled);
// Should always be shown if target system is not SCP and is URL for both CLI and YUI
expect(
showClientQuestion({
scp: false,
clientChoice: ClientChoiceValue.Blank,
targetSystem: TargetSystemType.Url,
url: '',
package: ''
})
).toBe(true);
PromptState.resetAbapDeployConfig();
}
);

test('should show client question (CLI)', () => {
PromptState.isYUI = false;
mockIsAppStudio.mockReturnValue(false);
expect(showClientQuestion(ClientChoiceValue.New, undefined, false)).toBe(true);
expect(
showClientQuestion({
clientChoice: ClientChoiceValue.New,
targetSystem: TargetSystemType.Url,
url: '',
package: ''
})
).toBe(true);
});

test('should show username question', async () => {
Expand Down
Loading
Loading