From ce7c99f7ebfad8c720c77ce3dd6f59d366d24715 Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Thu, 14 Sep 2023 22:14:35 +0200 Subject: [PATCH] Refactor inquirer to new package structure. Closes #5510 --- npm-shrinkwrap.json | 453 ++++++++++-------- package.json | 5 +- src/Command.ts | 32 +- src/chili/chili.spec.ts | 434 ++++++++++------- src/chili/chili.ts | 93 ++-- src/cli/Cli.spec.ts | 113 ++--- src/cli/Cli.ts | 64 ++- src/m365/aad/commands/app/app-remove.spec.ts | 28 +- src/m365/aad/commands/app/app-remove.ts | 9 +- .../aad/commands/app/app-role-remove.spec.ts | 49 +- src/m365/aad/commands/app/app-role-remove.ts | 9 +- .../approleassignment-remove.spec.ts | 39 +- .../approleassignment-remove.ts | 12 +- .../aad/commands/group/group-remove.spec.ts | 45 +- src/m365/aad/commands/group/group-remove.ts | 9 +- .../groupsetting/groupsetting-remove.spec.ts | 39 +- .../groupsetting/groupsetting-remove.ts | 9 +- .../m365group-recyclebinitem-clear.spec.ts | 42 +- .../m365group-recyclebinitem-clear.ts | 9 +- .../m365group-recyclebinitem-remove.spec.ts | 41 +- .../m365group-recyclebinitem-remove.ts | 9 +- .../m365group-recyclebinitem-restore.spec.ts | 7 + .../m365group/m365group-remove.spec.ts | 55 +-- .../commands/m365group/m365group-remove.ts | 9 +- .../m365group/m365group-user-remove.spec.ts | 61 +-- .../m365group/m365group-user-remove.ts | 9 +- .../oauth2grant/oauth2grant-remove.spec.ts | 45 +- .../oauth2grant/oauth2grant-remove.ts | 9 +- .../siteclassification-disable.spec.ts | 28 +- .../siteclassification-disable.ts | 9 +- .../commands/user/user-license-remove.spec.ts | 30 +- .../aad/commands/user/user-license-remove.ts | 9 +- .../user/user-recyclebinitem-clear.spec.ts | 26 +- .../user/user-recyclebinitem-clear.ts | 9 +- .../user/user-recyclebinitem-remove.spec.ts | 26 +- .../user/user-recyclebinitem-remove.ts | 9 +- .../aad/commands/user/user-remove.spec.ts | 30 +- src/m365/aad/commands/user/user-remove.ts | 9 +- .../permission/permission-add.spec.ts | 7 + .../commands/business/business-get.spec.ts | 7 + src/m365/commands/setup.spec.ts | 216 +++++++-- src/m365/commands/setup.ts | 75 ++- .../context/commands/context-remove.spec.ts | 26 +- src/m365/context/commands/context-remove.ts | 9 +- .../commands/option/option-remove.spec.ts | 26 +- .../context/commands/option/option-remove.ts | 9 +- src/m365/flow/commands/flow-remove.spec.ts | 55 +-- src/m365/flow/commands/flow-remove.ts | 9 +- .../flow/commands/owner/owner-remove.spec.ts | 28 +- src/m365/flow/commands/owner/owner-remove.ts | 11 +- src/m365/flow/commands/run/run-cancel.spec.ts | 42 +- src/m365/flow/commands/run/run-cancel.ts | 9 +- .../flow/commands/run/run-resubmit.spec.ts | 42 +- src/m365/flow/commands/run/run-resubmit.ts | 9 +- .../schemaextension-remove.spec.ts | 26 +- .../schemaextension/schemaextension-remove.ts | 9 +- .../onenote/commands/page/page-list.spec.ts | 7 + .../pa/commands/app/app-consent-set.spec.ts | 30 +- src/m365/pa/commands/app/app-consent-set.ts | 11 +- .../app/app-permission-remove.spec.ts | 21 +- .../pa/commands/app/app-permission-remove.ts | 11 +- src/m365/pa/commands/app/app-remove.spec.ts | 46 +- src/m365/pa/commands/app/app-remove.ts | 9 +- .../commands/bucket/bucket-get.spec.ts | 11 +- .../commands/bucket/bucket-remove.spec.ts | 41 +- .../planner/commands/bucket/bucket-remove.ts | 9 +- .../commands/bucket/bucket-set.spec.ts | 7 + .../planner/commands/plan/plan-remove.spec.ts | 32 +- src/m365/planner/commands/plan/plan-remove.ts | 10 +- .../roster/roster-member-remove.spec.ts | 49 +- .../commands/roster/roster-member-remove.ts | 20 +- .../commands/roster/roster-remove.spec.ts | 26 +- .../planner/commands/roster/roster-remove.ts | 10 +- .../task/task-checklistitem-remove.spec.ts | 30 +- .../task/task-checklistitem-remove.ts | 9 +- .../planner/commands/task/task-get.spec.ts | 7 + .../planner/commands/task/task-list.spec.ts | 7 + .../task/task-reference-remove.spec.ts | 30 +- .../commands/task/task-reference-remove.ts | 9 +- .../planner/commands/task/task-remove.spec.ts | 44 +- src/m365/planner/commands/task/task-remove.ts | 9 +- .../planner/commands/task/task-set.spec.ts | 7 + .../aibuildermodel/aibuildermodel-get.spec.ts | 7 + .../aibuildermodel-remove.spec.ts | 34 +- .../aibuildermodel/aibuildermodel-remove.ts | 9 +- src/m365/pp/commands/card/card-clone.spec.ts | 2 +- src/m365/pp/commands/card/card-get.spec.ts | 7 + src/m365/pp/commands/card/card-remove.spec.ts | 34 +- src/m365/pp/commands/card/card-remove.ts | 9 +- .../pp/commands/chatbot/chatbot-get.spec.ts | 7 + .../commands/chatbot/chatbot-remove.spec.ts | 28 +- .../pp/commands/chatbot/chatbot-remove.ts | 9 +- .../dataverse/dataverse-table-remove.spec.ts | 28 +- .../dataverse/dataverse-table-remove.ts | 9 +- .../dataverse-table-row-remove.spec.ts | 34 +- .../dataverse/dataverse-table-row-remove.ts | 9 +- .../solution/solution-publish.spec.ts | 2 +- .../solution-publisher-remove.spec.ts | 26 +- .../solution/solution-publisher-remove.ts | 9 +- .../commands/solution/solution-remove.spec.ts | 28 +- .../pp/commands/solution/solution-remove.ts | 9 +- .../retentionevent-remove.spec.ts | 26 +- .../retentionevent/retentionevent-remove.ts | 9 +- .../retentioneventtype-remove.spec.ts | 26 +- .../retentioneventtype-remove.ts | 9 +- .../retentionlabel-remove.spec.ts | 28 +- .../retentionlabel/retentionlabel-remove.ts | 9 +- .../externalconnection-remove.spec.ts | 42 +- .../externalconnection-remove.ts | 9 +- src/m365/spo/commands/app/app-deploy.spec.ts | 2 +- src/m365/spo/commands/app/app-remove.spec.ts | 26 +- src/m365/spo/commands/app/app-remove.ts | 9 +- src/m365/spo/commands/app/app-retract.spec.ts | 30 +- src/m365/spo/commands/app/app-retract.ts | 9 +- .../spo/commands/app/app-uninstall.spec.ts | 26 +- src/m365/spo/commands/app/app-uninstall.ts | 9 +- .../applicationcustomizer-remove.spec.ts | 32 +- .../applicationcustomizer-remove.ts | 9 +- .../applicationcustomizer-set.spec.ts | 7 + .../commands/cdn/cdn-origin-remove.spec.ts | 26 +- .../spo/commands/cdn/cdn-origin-remove.ts | 9 +- .../commandset/commandset-get.spec.ts | 7 + .../commandset/commandset-remove.spec.ts | 34 +- .../commands/commandset/commandset-remove.ts | 9 +- .../contenttype-field-remove.spec.ts | 98 ++-- .../contenttype/contenttype-field-remove.ts | 9 +- .../contenttype/contenttype-remove.spec.ts | 41 +- .../contenttype/contenttype-remove.ts | 4 +- .../customaction/customaction-clear.spec.ts | 26 +- .../customaction/customaction-clear.ts | 9 +- .../customaction/customaction-get.spec.ts | 7 + .../customaction/customaction-remove.spec.ts | 35 +- .../customaction/customaction-remove.ts | 9 +- .../eventreceiver/eventreceiver-get.spec.ts | 7 + .../eventreceiver-remove.spec.ts | 40 +- .../eventreceiver/eventreceiver-remove.ts | 9 +- .../spo/commands/field/field-remove.spec.ts | 43 +- src/m365/spo/commands/field/field-remove.ts | 9 +- .../commands/file/file-checkout-undo.spec.ts | 27 +- .../spo/commands/file/file-checkout-undo.ts | 9 +- src/m365/spo/commands/file/file-copy.spec.ts | 7 + .../spo/commands/file/file-remove.spec.ts | 92 ++-- src/m365/spo/commands/file/file-remove.ts | 9 +- .../file/file-retentionlabel-remove.spec.ts | 29 +- .../file/file-retentionlabel-remove.ts | 9 +- .../file/file-roleassignment-remove.spec.ts | 26 +- .../file/file-roleassignment-remove.ts | 9 +- .../file/file-roleinheritance-break.spec.ts | 26 +- .../file/file-roleinheritance-break.ts | 9 +- .../file/file-roleinheritance-reset.spec.ts | 26 +- .../file/file-roleinheritance-reset.ts | 9 +- .../file/file-sharinglink-clear.spec.ts | 37 +- .../commands/file/file-sharinglink-clear.ts | 9 +- .../file/file-sharinglink-remove.spec.ts | 30 +- .../commands/file/file-sharinglink-remove.ts | 9 +- .../commands/file/file-version-clear.spec.ts | 34 +- .../spo/commands/file/file-version-clear.ts | 11 +- .../commands/file/file-version-remove.spec.ts | 34 +- .../spo/commands/file/file-version-remove.ts | 11 +- .../file/file-version-restore.spec.ts | 36 +- .../spo/commands/file/file-version-restore.ts | 11 +- .../spo/commands/folder/folder-remove.spec.ts | 38 +- src/m365/spo/commands/folder/folder-remove.ts | 9 +- .../folder-retentionlabel-remove.spec.ts | 29 +- .../folder/folder-retentionlabel-remove.ts | 9 +- .../folder-roleassignment-remove.spec.ts | 21 +- .../folder/folder-roleassignment-remove.ts | 9 +- .../folder-roleinheritance-break.spec.ts | 34 +- .../folder/folder-roleinheritance-break.ts | 9 +- .../folder-roleinheritance-reset.spec.ts | 32 +- .../folder/folder-roleinheritance-reset.ts | 9 +- .../group/group-member-remove.spec.ts | 46 +- .../spo/commands/group/group-member-remove.ts | 9 +- .../spo/commands/group/group-remove.spec.ts | 24 +- src/m365/spo/commands/group/group-remove.ts | 9 +- .../hidedefaultthemes-set.spec.ts | 7 + .../commands/homesite/homesite-remove.spec.ts | 30 +- .../spo/commands/homesite/homesite-remove.ts | 9 +- .../commands/hubsite/hubsite-connect.spec.ts | 7 + .../hubsite/hubsite-disconnect.spec.ts | 29 +- .../commands/hubsite/hubsite-disconnect.ts | 9 +- .../spo/commands/hubsite/hubsite-get.spec.ts | 7 + .../hubsite/hubsite-rights-revoke.spec.ts | 32 +- .../commands/hubsite/hubsite-rights-revoke.ts | 9 +- .../hubsite/hubsite-unregister.spec.ts | 26 +- .../commands/hubsite/hubsite-unregister.ts | 9 +- .../knowledgehub/knowledgehub-remove.spec.ts | 26 +- .../knowledgehub/knowledgehub-remove.ts | 9 +- .../list/list-contenttype-remove.spec.ts | 54 +-- .../commands/list/list-contenttype-remove.ts | 9 +- .../spo/commands/list/list-remove.spec.ts | 30 +- src/m365/spo/commands/list/list-remove.ts | 9 +- .../list/list-retentionlabel-remove.spec.ts | 59 +-- .../list/list-retentionlabel-remove.ts | 9 +- .../list/list-roleassignment-remove.spec.ts | 33 +- .../list/list-roleassignment-remove.ts | 9 +- .../list/list-roleinheritance-break.spec.ts | 30 +- .../list/list-roleinheritance-break.ts | 9 +- .../list/list-roleinheritance-reset.spec.ts | 30 +- .../list/list-roleinheritance-reset.ts | 9 +- .../list/list-sensitivitylabel-ensure.spec.ts | 7 + .../list/list-view-field-remove.spec.ts | 57 +-- .../commands/list/list-view-field-remove.ts | 9 +- .../commands/list/list-view-remove.spec.ts | 73 ++- .../spo/commands/list/list-view-remove.ts | 9 +- .../commands/list/list-webhook-remove.spec.ts | 57 +-- .../spo/commands/list/list-webhook-remove.ts | 9 +- .../commands/listitem/listitem-remove.spec.ts | 46 +- .../spo/commands/listitem/listitem-remove.ts | 9 +- .../listitem-retentionlabel-remove.spec.ts | 41 +- .../listitem-retentionlabel-remove.ts | 9 +- .../listitem-roleassignment-remove.spec.ts | 28 +- .../listitem-roleassignment-remove.ts | 9 +- .../listitem-roleinheritance-break.spec.ts | 34 +- .../listitem-roleinheritance-break.ts | 9 +- .../listitem-roleinheritance-reset.spec.ts | 34 +- .../listitem-roleinheritance-reset.ts | 9 +- .../navigation/navigation-node-remove.spec.ts | 30 +- .../navigation/navigation-node-remove.ts | 9 +- .../orgassetslibrary-remove.spec.ts | 40 +- .../orgassetslibrary-remove.ts | 9 +- .../orgnewssite/orgnewssite-remove.spec.ts | 30 +- .../orgnewssite/orgnewssite-remove.ts | 9 +- .../spo/commands/page/page-remove.spec.ts | 49 +- src/m365/spo/commands/page/page-remove.ts | 12 +- .../propertybag/propertybag-remove.spec.ts | 30 +- .../propertybag/propertybag-remove.ts | 9 +- .../roledefinition-remove.spec.ts | 29 +- .../roledefinition/roledefinition-remove.ts | 9 +- .../serviceprincipal-set.spec.ts | 35 +- .../serviceprincipal/serviceprincipal-set.ts | 9 +- .../site/site-apppermission-remove.spec.ts | 43 +- .../site/site-apppermission-remove.ts | 9 +- .../site/site-commsite-enable.spec.ts | 7 + .../site/site-hubsite-disconnect.spec.ts | 36 +- .../commands/site/site-hubsite-disconnect.ts | 9 +- .../site/site-recyclebinitem-clear.spec.ts | 32 +- .../site/site-recyclebinitem-clear.ts | 9 +- .../site/site-recyclebinitem-move.spec.ts | 32 +- .../commands/site/site-recyclebinitem-move.ts | 9 +- .../site/site-recyclebinitem-remove.spec.ts | 30 +- .../site/site-recyclebinitem-remove.ts | 9 +- .../spo/commands/site/site-remove.spec.ts | 24 +- src/m365/spo/commands/site/site-remove.ts | 9 +- .../sitedesign/sitedesign-remove.spec.ts | 28 +- .../commands/sitedesign/sitedesign-remove.ts | 9 +- .../sitedesign-rights-revoke.spec.ts | 28 +- .../sitedesign/sitedesign-rights-revoke.ts | 9 +- .../sitedesign/sitedesign-task-remove.spec.ts | 28 +- .../sitedesign/sitedesign-task-remove.ts | 9 +- .../sitescript/sitescript-remove.spec.ts | 28 +- .../commands/sitescript/sitescript-remove.ts | 9 +- .../storageentity-remove.spec.ts | 35 +- .../storageentity/storageentity-remove.ts | 9 +- ...enant-applicationcustomizer-remove.spec.ts | 65 ++- .../tenant-applicationcustomizer-remove.ts | 9 +- .../tenant/tenant-commandset-get.spec.ts | 7 + .../tenant/tenant-commandset-remove.spec.ts | 66 ++- .../tenant/tenant-commandset-remove.ts | 9 +- .../tenant-recyclebinitem-remove.spec.ts | 12 +- .../tenant/tenant-recyclebinitem-remove.ts | 9 +- .../spo/commands/theme/theme-remove.spec.ts | 30 +- src/m365/spo/commands/theme/theme-remove.ts | 9 +- .../spo/commands/user/user-remove.spec.ts | 35 +- src/m365/spo/commands/user/user-remove.ts | 9 +- src/m365/spo/commands/web/web-remove.spec.ts | 24 +- src/m365/spo/commands/web/web-remove.ts | 9 +- .../web/web-roleassignment-remove.spec.ts | 23 +- .../commands/web/web-roleassignment-remove.ts | 9 +- .../web/web-roleinheritance-break.spec.ts | 23 +- .../commands/web/web-roleinheritance-break.ts | 9 +- .../web/web-roleinheritance-reset.spec.ts | 23 +- .../commands/web/web-roleinheritance-reset.ts | 9 +- .../teams/commands/app/app-remove.spec.ts | 6 +- src/m365/teams/commands/app/app-remove.ts | 9 +- .../teams/commands/app/app-uninstall.spec.ts | 6 +- src/m365/teams/commands/app/app-uninstall.ts | 9 +- .../teams/commands/cache/cache-remove.spec.ts | 30 +- src/m365/teams/commands/cache/cache-remove.ts | 11 +- .../channel/channel-member-add.spec.ts | 7 + .../channel/channel-member-remove.spec.ts | 36 +- .../commands/channel/channel-member-remove.ts | 9 +- .../commands/channel/channel-remove.spec.ts | 38 +- .../teams/commands/channel/channel-remove.ts | 9 +- .../commands/chat/chat-member-remove.spec.ts | 26 +- .../teams/commands/chat/chat-member-remove.ts | 9 +- .../teams/commands/tab/tab-remove.spec.ts | 35 +- src/m365/teams/commands/tab/tab-remove.ts | 9 +- .../teams/commands/team/team-remove.spec.ts | 39 +- src/m365/teams/commands/team/team-remove.ts | 9 +- .../commands/user/user-app-remove.spec.ts | 21 +- .../teams/commands/user/user-app-remove.ts | 9 +- .../todo/commands/list/list-remove.spec.ts | 25 +- src/m365/todo/commands/list/list-remove.ts | 9 +- .../todo/commands/task/task-remove.spec.ts | 24 +- src/m365/todo/commands/task/task-remove.ts | 9 +- .../commands/group/group-user-add.spec.ts | 6 +- .../commands/group/group-user-remove.spec.ts | 22 +- .../commands/group/group-user-remove.ts | 9 +- .../commands/message/message-like-set.spec.ts | 34 +- .../commands/message/message-like-set.ts | 11 +- .../commands/message/message-remove.spec.ts | 10 +- .../yammer/commands/message/message-remove.ts | 9 +- src/utils/aadGroup.spec.ts | 10 +- src/utils/prompt.ts | 60 ++- 305 files changed, 3245 insertions(+), 4300 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 7a8917190c6..4150bdf60b4 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -11,6 +11,9 @@ "dependencies": { "@azure/msal-common": "^13.2.1", "@azure/msal-node": "^1.18.1", + "@inquirer/confirm": "^2.0.12", + "@inquirer/input": "^1.2.11", + "@inquirer/select": "^1.2.11", "@xmldom/xmldom": "^0.8.10", "adaptive-expressions": "^4.20.0", "adaptivecards": "^3.0.1", @@ -23,7 +26,6 @@ "configstore": "^6.0.0", "csv-stringify": "^6.4.0", "easy-table": "^1.2.0", - "inquirer": "^9.2.10", "jmespath": "^0.16.0", "json-to-ast": "^2.1.0", "minimist": "^1.2.8", @@ -47,7 +49,6 @@ "devDependencies": { "@microsoft/microsoft-graph-types": "^2.38.0", "@types/adm-zip": "^0.5.0", - "@types/inquirer": "^9.0.3", "@types/jmespath": "^0.15.0", "@types/json-to-ast": "^2.1.2", "@types/minimist": "^1.2.2", @@ -323,6 +324,242 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@inquirer/confirm": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-2.0.12.tgz", + "integrity": "sha512-Oxz3L0ti+0nWYHPPUIrPkxA2KnQZUGBHnk56yF5RjKqPGFrwvgLZdIXNe/w4I/OtdLeOBqHCrJ+kCvNvHVdk9g==", + "dependencies": { + "@inquirer/core": "^5.0.0", + "@inquirer/type": "^1.1.4", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/confirm/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/confirm/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@inquirer/core": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-5.0.0.tgz", + "integrity": "sha512-q2o4BcANKFyuUI5V6ejmPs1f9SdbJxfnLmhQVb72Fj7hOudoKsJpByJZ0imv9a/rpKDogA+93vtBBMqsnS7/Fg==", + "dependencies": { + "@inquirer/type": "^1.1.4", + "@types/mute-stream": "^0.0.1", + "@types/node": "^20.6.0", + "@types/wrap-ansi": "^3.0.0", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "cli-spinners": "^2.9.0", + "cli-width": "^4.1.0", + "figures": "^3.2.0", + "mute-stream": "^1.0.0", + "run-async": "^3.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/core/node_modules/@types/node": { + "version": "20.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.3.tgz", + "integrity": "sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==" + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/input": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-1.2.11.tgz", + "integrity": "sha512-sV1nO6+RxMFTHAznmxMkbMkjGQ8NGMWr0mvXjU35YQ0OFEL+YlD+DPbNd9s3ltnswODZAcnM1yFvdko3S/Kj/w==", + "dependencies": { + "@inquirer/core": "^5.0.0", + "@inquirer/type": "^1.1.4", + "chalk": "^4.1.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/input/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/input/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@inquirer/select": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-1.2.11.tgz", + "integrity": "sha512-LH2wzAsWfu/+wcapeht07zTDefuvGTpv0+9dCAQ68QigF+4gHzpWq5+AbBLbxzuH2Wz4WlHcti85nFUPPM1t3A==", + "dependencies": { + "@inquirer/core": "^5.0.0", + "@inquirer/type": "^1.1.4", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "figures": "^3.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/@inquirer/select/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/select/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@inquirer/type": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.1.4.tgz", + "integrity": "sha512-a6+RCiXBQEbiA73RT1pBfwiH2I+MPcoZoGKuuUYFkws+6ud7nb5kUQGHFGUSBim25IyVMT/mqbWIrkxetcIb/w==", + "engines": { + "node": ">=14.18.0" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -357,14 +594,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@ljharb/through": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.9.tgz", - "integrity": "sha512-yN599ZBuMPPK4tdoToLlvgJB4CLK8fGl7ntfy0Wn7U6ttNvHYurd81bfUiK/6sMkiIwm65R6ck4L6+Y3DfVbNQ==", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/@microsoft/applicationinsights-web-snippet": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@microsoft/applicationinsights-web-snippet/-/applicationinsights-web-snippet-1.0.1.tgz", @@ -639,16 +868,6 @@ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, - "node_modules/@types/inquirer": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.3.tgz", - "integrity": "sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==", - "dev": true, - "dependencies": { - "@types/through": "*", - "rxjs": "^7.2.0" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -703,11 +922,18 @@ "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", "dev": true }, + "node_modules/@types/mute-stream": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.1.tgz", + "integrity": "sha512-0yQLzYhCqGz7CQPE3iDmYjhb7KMBFOP+tBkyw+/Y2YyDI5wpS7itXXxneN1zSsUwWx3Ji6YiVYrhAnpQGS/vkw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "18.17.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.14.tgz", - "integrity": "sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw==", - "dev": true + "integrity": "sha512-ZE/5aB73CyGqgQULkLG87N9GnyGe5TcQjv34pwS8tfBs1IkCh0ASM69mydb2znqd6v0eX+9Ytvk6oQRqu8T1Vw==" }, "node_modules/@types/node-forge": { "version": "1.3.4", @@ -750,15 +976,6 @@ "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", "dev": true }, - "node_modules/@types/through": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", - "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/update-notifier": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/@types/update-notifier/-/update-notifier-6.0.5.tgz", @@ -775,6 +992,11 @@ "integrity": "sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug==", "dev": true }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==" + }, "node_modules/@types/xmldom": { "version": "0.1.31", "resolved": "https://registry.npmjs.org/@types/xmldom/-/xmldom-0.1.31.tgz", @@ -1539,11 +1761,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -2190,8 +2407,9 @@ } }, "node_modules/eslint-plugin-cli-microsoft365": { - "resolved": "eslint-rules", - "link": true + "version": "1.0.0", + "resolved": "file:eslint-rules", + "dev": true }, "node_modules/eslint-plugin-mocha": { "version": "10.1.0", @@ -2416,19 +2634,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2506,29 +2711,25 @@ } }, "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=14" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/figures/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/file-entry-cache": { @@ -2941,17 +3142,6 @@ "node": ">=10.17.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3046,76 +3236,6 @@ "node": ">=10" } }, - "node_modules/inquirer": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.10.tgz", - "integrity": "sha512-tVVNFIXU8qNHoULiazz612GFl+yqNfjMTbLuViNJE/d860Qxrd3NMrse8dm40VUQLOQeULvaQF8lpAhvysjeyA==", - "dependencies": { - "@ljharb/through": "^2.3.9", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/inquirer/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3277,17 +3397,6 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, - "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -4038,14 +4147,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -4552,14 +4653,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4579,11 +4672,6 @@ } ] }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4882,17 +4970,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index a514c093091..2ad44df11fb 100644 --- a/package.json +++ b/package.json @@ -226,6 +226,9 @@ "dependencies": { "@azure/msal-common": "^13.2.1", "@azure/msal-node": "^1.18.1", + "@inquirer/confirm": "^2.0.12", + "@inquirer/input": "^1.2.11", + "@inquirer/select": "^1.2.11", "@xmldom/xmldom": "^0.8.10", "adaptive-expressions": "^4.20.0", "adaptivecards": "^3.0.1", @@ -238,7 +241,6 @@ "configstore": "^6.0.0", "csv-stringify": "^6.4.0", "easy-table": "^1.2.0", - "inquirer": "^9.2.10", "jmespath": "^0.16.0", "json-to-ast": "^2.1.0", "minimist": "^1.2.8", @@ -256,7 +258,6 @@ "devDependencies": { "@microsoft/microsoft-graph-types": "^2.38.0", "@types/adm-zip": "^0.5.0", - "@types/inquirer": "^9.0.3", "@types/jmespath": "^0.15.0", "@types/json-to-ast": "^2.1.2", "@types/minimist": "^1.2.2", diff --git a/src/Command.ts b/src/Command.ts index 716d73ae4df..e1677dcb31c 100644 --- a/src/Command.ts +++ b/src/Command.ts @@ -166,12 +166,9 @@ export default abstract class Command { Cli.error('🌶️ Provide values for the following parameters:'); } - const missingRequireOptionValue = await prompt.forInput<{ missingRequireOptionValue: string }>({ - name: 'missingRequireOptionValue', - message: `${command.options[i].name}: ` - }).then(result => result.missingRequireOptionValue); + const answer = await prompt.forInput({ message: `${command.options[i].name}: ` }); - args.options[command.options[i].name] = missingRequireOptionValue; + args.options[command.options[i].name] = answer; } if (prompted) { @@ -222,34 +219,19 @@ export default abstract class Command { private async promptForOptionSetNameAndValue(args: CommandArgs, optionSet: OptionSet): Promise { Cli.error(`🌶️ Please specify one of the following options:`); - const resultOptionName = await prompt.forInput<{ missingRequiredOptionName: string }>({ - type: 'list', - name: 'missingRequiredOptionName', - message: `Option to use:`, - choices: optionSet.options - }); - const missingRequiredOptionName = resultOptionName.missingRequiredOptionName; - - const resultOptionValue = await prompt.forInput<{ missingRequiredOptionValue: string }>({ - name: 'missingRequiredOptionValue', - message: `${missingRequiredOptionName}:` - }); + const selectedOptionName = await prompt.forSelection({ message: `Option to use:`, choices: optionSet.options.map((choice: any) => { return { name: choice, value: choice }; }) }); + const optionValue = await prompt.forInput({ message: `${selectedOptionName}:` }); - args.options[missingRequiredOptionName] = resultOptionValue.missingRequiredOptionValue; + args.options[selectedOptionName] = optionValue; Cli.error(''); } private async promptForSpecificOption(args: CommandArgs, commonOptions: string[]): Promise { Cli.error(`🌶️ Multiple options for an option set specified. Please specify the correct option that you wish to use.`); - const requiredOptionNameResult = await prompt.forInput<{ missingRequiredOptionName: string }>({ - type: 'list', - name: 'missingRequiredOptionName', - message: `Option to use:`, - choices: commonOptions - }); + const selectedOptionName = await prompt.forSelection({ message: `Option to use:`, choices: commonOptions.map((choice: any) => { return { name: choice, value: choice }; }) }); - commonOptions.filter(y => y !== requiredOptionNameResult.missingRequiredOptionName).map(optionName => args.options[optionName] = undefined); + commonOptions.filter(y => y !== selectedOptionName).map(optionName => args.options[optionName] = undefined); Cli.error(''); } diff --git a/src/chili/chili.spec.ts b/src/chili/chili.spec.ts index 3a6ecf9fbf5..5d7f71f35d4 100644 --- a/src/chili/chili.spec.ts +++ b/src/chili/chili.spec.ts @@ -1,10 +1,10 @@ import assert from 'assert'; import fs from 'fs'; -import inquirer from 'inquirer'; import sinon from 'sinon'; import { chili } from './chili.js'; import request from '../request.js'; import { sinonUtil } from '../utils/sinonUtil.js'; +import { SelectionConfig, prompt } from '../utils/prompt.js'; describe('chili', () => { let consoleLogSpy: sinon.SinonStub; @@ -20,8 +20,9 @@ describe('chili', () => { consoleErrorSpy.resetHistory(); sinonUtil.restore([ - inquirer.prompt, request.post, + prompt.forSelection, + prompt.forInput, fs.existsSync ]); }); @@ -53,14 +54,26 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').resolves({}); - assert.doesNotReject(chili.startConversation(['Hello'])); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; + }); + await assert.doesNotReject(chili.startConversation(['Hello'])); }); - it('starts a conversation when a prompt specified as a single arg', () => { + it('starts a conversation when a prompt specified as a single arg', async () => { sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -78,14 +91,26 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); + } + throw `Invalid request: ${options.url}`; + }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; } - return Promise.reject('Invalid request'); + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; }); - sinon.stub(inquirer, 'prompt').resolves({}); - assert.doesNotReject(chili.startConversation(['Hello world'])); + await assert.doesNotReject(chili.startConversation(['Hello world'])); }); - it('starts a conversation when a prompt specified as multiple args (no quotes)', () => { + it('starts a conversation when a prompt specified as multiple args (no quotes)', async () => { sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -103,14 +128,26 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); + } + throw `Invalid request: ${options.url}`; + }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; } - return Promise.reject('Invalid request'); + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; }); - sinon.stub(inquirer, 'prompt').resolves({}); - assert.doesNotReject(chili.startConversation(['Hello', 'world'])); + await assert.doesNotReject(chili.startConversation(['Hello', 'world'])); }); - it('starts a conversation asking for a prompt when no prompt specified via args', () => { + it('starts a conversation asking for a prompt when no prompt specified via args', async () => { sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -128,21 +165,26 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation([])); + await assert.doesNotReject(chili.startConversation([])); }); - it('uses the prompt to search in CLI docs using Mendable', () => { + it('uses the prompt to search in CLI docs using Mendable', async () => { sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -160,11 +202,22 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); + } + throw `Invalid request: ${options.url}`; + }); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.reject('Invalid request'); + + throw `Prompt not found for '${config.message}'`; }); - sinon.stub(inquirer, 'prompt').resolves({}); - assert.doesNotReject(chili.startConversation(['Hello'])); + await assert.doesNotReject(chili.startConversation(['Hello'])); }); it('displays the retrieved response to the user', async () => { @@ -185,11 +238,23 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); + } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').resolves({}); - await chili.startConversation(['Hello']); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; + }); + await chili.startConversation(['Hello', '--no-rating']); assert(consoleLogSpy.calledWith('Hello back')); }); @@ -211,10 +276,21 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; + }); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; }); - sinon.stub(inquirer, 'prompt').resolves({}); await chili.startConversation(['Hello']); assert(consoleLogSpy.calledWith('Hello back')); }); @@ -241,10 +317,21 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; + }); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; + } + + throw `Prompt not found for '${config.message}'`; }); - sinon.stub(inquirer, 'prompt').resolves({}); await chili.startConversation(['Hello']); assert(consoleLogSpy.calledWith('⬥ https://example.com/source-1')); }); @@ -272,19 +359,22 @@ describe('chili', () => { break; case 'https://api.mendable.ai/v0/rateMessage': return Promise.resolve({}); + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); - } - if (questions[0].name === 'rating') { + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { promptedForRating = true; + return 1; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); await chili.startConversation(['Hello world']); assert.strictEqual(promptedForRating, true); @@ -311,19 +401,22 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); - } - if (questions[0].name === 'rating') { + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { promptedForRating = true; + return 1; + } + else if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); await chili.startConversation(['Hello world', '--no-rating']); assert.strictEqual(promptedForRating, false); @@ -354,26 +447,26 @@ describe('chili', () => { return Promise.resolve({}); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 1; } - if (questions[0].name === 'rating') { - return Promise.resolve({ - rating: 1 - }); + if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello world'])); + await assert.doesNotReject(chili.startConversation(['Hello world'])); }); - it('sends negative rating to Mendable', () => { + it('sends negative rating to Mendable', async () => { sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -398,23 +491,23 @@ describe('chili', () => { return Promise.resolve({}); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return -1; } - if (questions[0].name === 'rating') { - return Promise.resolve({ - rating: -1 - }); + if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello world'])); + await assert.doesNotReject(chili.startConversation(['Hello world'])); }); it(`doesn't send rating to Mendable when user chose to skip`, async () => { @@ -437,23 +530,23 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 0; } - if (questions[0].name === 'rating') { - return Promise.resolve({ - rating: 0 - }); + if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello world'])); + await assert.doesNotReject(chili.startConversation(['Hello world'])); }); it(`doesn't fail when rating the response failed`, async () => { @@ -478,23 +571,23 @@ describe('chili', () => { break; case 'https://api.mendable.ai/v0/rateMessage': return Promise.reject('An error has occurred'); + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 1; } - if (questions[0].name === 'rating') { - return Promise.resolve({ - rating: 1 - }); + if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello world'])); + await assert.doesNotReject(chili.startConversation(['Hello world'])); }); it(`when rating the response failed, shows error in debug mode`, async () => { @@ -519,28 +612,28 @@ describe('chili', () => { break; case 'https://api.mendable.ai/v0/rateMessage': return Promise.reject('An error has occurred'); + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'prompt') { - return Promise.resolve({ - prompt: 'Hello world' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'Was this helpful?') { + return 1; } - if (questions[0].name === 'rating') { - return Promise.resolve({ - rating: 1 - }); + else if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); await chili.startConversation(['Hello world', '--debug']); assert(consoleErrorSpy.calledWith('An error has occurred while rating the response: An error has occurred')); }); it('allows asking a follow-up question after a response', async () => { - let i = 0; + let questionsAsked = 0; sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -549,6 +642,7 @@ describe('chili', () => { conversation_id: 1 }); case 'https://api.mendable.ai/v0/mendableChat': + questionsAsked++; if (options.data.question === 'Hello') { return Promise.resolve({ answer: { @@ -569,32 +663,26 @@ describe('chili', () => { case 'https://api.mendable.ai/v0/endConversation': return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - switch (questions[0].name) { - case 'chat': - if (i++ === 0) { - return Promise.resolve({ - chat: 'ask' - }); - } - else { - return Promise.resolve({ - chat: 'end' - }); - } - case 'prompt': - return Promise.resolve({ - prompt: 'Follow up' - }); + sinon.stub(prompt, 'forInput').resolves('Follow up'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'What would you like to do next?') { + if (questionsAsked === 1) { + return 'ask'; + } + else { + return 'end'; + } } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); + await assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); }); it('for a follow-up question, includes the history', async () => { + let questionsAsked = 0; sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': @@ -603,6 +691,7 @@ describe('chili', () => { conversation_id: 1 }); case 'https://api.mendable.ai/v0/mendableChat': + questionsAsked++; if (options.data.question === 'Hello') { return Promise.resolve({ answer: { @@ -613,7 +702,7 @@ describe('chili', () => { } if (options.data.question === 'Follow up' && options.data.history[0].prompt === 'Hello' && - options.data.history[0].answer === 'Hello back') { + options.data.history[0].response === 'Hello back') { return Promise.resolve({ answer: { text: 'Hello again' @@ -622,23 +711,20 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - switch (questions[0].name) { - case 'chat': - return Promise.resolve({ - chat: 'ask' - }); - case prompt: - return Promise.resolve({ - prompt: 'Follow up' - }); + sinon.stub(prompt, 'forInput').resolves('Follow up'); + sinon.stub(prompt, 'forSelection').callsFake(async (config) => { + if (config.message === 'What would you like to do next?' && questionsAsked >= 2) { + return 'end'; } - return Promise.resolve({}); + + return 'ask'; }); - assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); + await assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); }); it('allows ending conversation after a response', async () => { @@ -659,28 +745,30 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - if (questions[0].name === 'chat') { - return Promise.resolve({ - chat: 'end' - }); + sinon.stub(prompt, 'forInput').resolves('Hello world'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'What would you like to do next?') { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); + await assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); }); it('allows starting a new conversation after a response', async () => { - let i = 0; + let conversationsStarted = 0; sinon.stub(request, 'post').callsFake(options => { switch (options.url) { case 'https://api.mendable.ai/v0/newConversation': return Promise.resolve({ // eslint-disable-next-line camelcase - conversation_id: ++i + conversation_id: ++conversationsStarted }); case 'https://api.mendable.ai/v0/mendableChat': if (options.data.question === 'Hello') { @@ -701,23 +789,23 @@ describe('chili', () => { }); } break; + case 'https://api.mendable.ai/v0/endConversation': + return Promise.resolve({}); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').callsFake((questions: any): any => { - switch (questions[0].name) { - case 'chat': - return Promise.resolve({ - chat: 'new' - }); - case 'prompt': - return Promise.resolve({ - prompt: 'Hello 2' - }); + sinon.stub(prompt, 'forInput').resolves('Hello 2'); + sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + if (config.message === 'What would you like to do next?' && conversationsStarted === 1) { + return 'new'; + } + if (config.message === 'What would you like to do next?' && conversationsStarted > 1) { + return 'end'; } - return Promise.resolve({}); + + throw `Prompt not found for '${config.message}'`; }); - assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); + await assert.doesNotReject(chili.startConversation(['Hello', '--no-rating'])); }); it('throws exception when getting conversation ID failed', async () => { @@ -726,9 +814,9 @@ describe('chili', () => { case 'https://api.mendable.ai/v0/newConversation': return Promise.reject('An error has occurred'); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').resolves({}); + sinon.stub(prompt, 'forSelection').resolves({}); assert.rejects(chili.startConversation(['Hello']), 'An error has occurred'); }); @@ -743,9 +831,9 @@ describe('chili', () => { case 'https://api.mendable.ai/v0/mendableChat': return Promise.reject('An error has occurred'); } - return Promise.reject('Invalid request'); + throw `Invalid request: ${options.url}`; }); - sinon.stub(inquirer, 'prompt').resolves({}); + sinon.stub(prompt, 'forSelection').resolves({}); assert.rejects(chili.startConversation(['Hello']), 'An error has occurred'); }); diff --git a/src/chili/chili.ts b/src/chili/chili.ts index 92637a4b17c..9e2916fb719 100644 --- a/src/chili/chili.ts +++ b/src/chili/chili.ts @@ -1,5 +1,4 @@ import fs from 'fs'; -import inquirer from 'inquirer'; import ora from 'ora'; import path from 'path'; import url from 'url'; @@ -7,6 +6,7 @@ import { Cli } from '../cli/Cli.js'; import request, { CliRequestOptions } from '../request.js'; import { settingsNames } from '../settingsNames.js'; import { md } from '../utils/md.js'; +import { prompt } from '../utils/prompt.js'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); @@ -118,12 +118,7 @@ async function startConversation(args: string[]): Promise { } async function promptForPrompt(): Promise { - const answer = await inquirer.prompt<{ prompt: string }>([{ - type: 'input', - name: 'prompt', - message: '🌶️ How can I help you?' - }]); - return answer.prompt; + return await prompt.forInput({ message: '🌶️ How can I help you?' }); } async function runConversationTurn(conversationId: number, question: string): Promise { @@ -169,63 +164,59 @@ async function runConversationTurn(conversationId: number, question: string): Pr console.log(''); } - const result = await inquirer.prompt<{ chat: string }>([{ - type: 'list', - name: 'chat', - message: 'What would you like to do next?', - choices: [ - { - name: '📝 I want to know more', - value: 'ask' - }, - { - name: '👋 I know enough. Thanks!', - value: 'end' - }, - { - name: '🔄 I want to ask about something else', - value: 'new' - } - ] - }]); + const choices = [ + { + name: '📝 I want to know more', + value: 'ask' + }, + { + name: '👋 I know enough. Thanks!', + value: 'end' + }, + { + name: '🔄 I want to ask about something else', + value: 'new' + } + ]; + + const result = await prompt.forSelection({ message: 'What would you like to do next?', choices }); - switch (result.chat) { + switch (result) { case 'ask': const prompt = await promptForPrompt(); - return await runConversationTurn(conversationId, prompt); + await runConversationTurn(conversationId, prompt); + break; case 'end': await endConversation(conversationId); console.log(''); console.log('🌶️ Bye!'); - return; + break; case 'new': initialPrompt = ''; - return startConversation([]); + await startConversation([]); + break; } } async function rateResponse(messageId: number): Promise { - const result = await inquirer.prompt<{ rating: number }>([{ - type: 'list', - name: 'rating', - message: 'Was this helpful?', - choices: [ - { - name: '👍 Yes', - value: 1 - }, - { - name: '👎 No', - value: -1 - }, - { - name: '🤔 Not sure/skip', - value: 0 - } - ] - }]); + const choices = [ + { + name: '👍 Yes', + value: 1 + }, + { + name: '👎 No', + value: -1 + }, + { + name: '🤔 Not sure/skip', + value: 0 + } + ]; + + const rating = await prompt.forSelection({ message: 'Was this helpful?', choices }); - if (result.rating === 0) { + if (rating === 0) { return; } @@ -246,7 +237,7 @@ async function rateResponse(messageId: number): Promise { // eslint-disable-next-line camelcase message_id: messageId, // eslint-disable-next-line camelcase - rating_value: result.rating + rating_value: rating } }; diff --git a/src/cli/Cli.spec.ts b/src/cli/Cli.spec.ts index 547de7dbe77..decbcbb3f32 100644 --- a/src/cli/Cli.spec.ts +++ b/src/cli/Cli.spec.ts @@ -2,7 +2,6 @@ import assert from 'assert'; import chalk from 'chalk'; import Table from 'easy-table'; import fs from 'fs'; -import { prompt } from '../utils/prompt.js'; import { createRequire } from 'module'; import os from 'os'; import path from 'path'; @@ -19,6 +18,7 @@ import { session } from '../utils/session.js'; import { sinonUtil } from '../utils/sinonUtil.js'; import { Cli, CommandOutput } from './Cli.js'; import { Logger } from './Logger.js'; +import { Choice, SelectionConfig, prompt } from '../utils/prompt.js'; const require = createRequire(import.meta.url); const packageJSON = require('../../package.json'); @@ -167,12 +167,7 @@ class MockCommandWithPrompt extends AnonymousCommand { return 'Mock command with prompt'; } public async commandAction(): Promise { - await Cli.prompt({ - type: 'confirm', - name: 'continue', - default: false, - message: `Continue?` - }); + await Cli.promptForConfirmation({ message: `Continue?` }); } } @@ -283,7 +278,6 @@ describe('Cli', () => { Cli.executeCommand, fs.existsSync, fs.readFileSync, - prompt.forInput, // eslint-disable-next-line no-console console.log, // eslint-disable-next-line no-console @@ -293,7 +287,9 @@ describe('Cli', () => { mockCommandWithValidation.validate, mockCommand.commandAction, mockCommand.processOptions, - Cli.prompt, + prompt.forInput, + prompt.forSelection, + prompt.forConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -828,7 +824,7 @@ describe('Cli', () => { }); it(`prompts for required options`, (done) => { - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake(() => Promise.resolve({ missingRequireOptionValue: "test" }) as any); + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').resolves("test"); sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { if (settingName === settingsNames.prompt) { return 'true'; @@ -851,20 +847,14 @@ describe('Cli', () => { it(`prompts for optionset name and value when optionset not specified`, async () => { let firstOptionValue = '', secondOptionValue = ''; - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake((opts: any, _) => { - if (opts.type === 'list' && opts.name === 'missingRequiredOptionName') { - firstOptionValue = opts.choices[0]; - secondOptionValue = opts.choices[1]; - return { missingRequiredOptionName: opts.choices[0] } as any; - } - - if (opts.name === 'missingRequiredOptionValue') { - return { missingRequiredOptionValue: 'Test 123' } as any; - } - - throw 'Specific prompt not found'; + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + firstOptionValue = (config.choices[0] as Choice).value; + secondOptionValue = (config.choices[1] as Choice).value; + return (config.choices[0] as Choice).value; }); + const promptInputStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').resolves('Test 123'); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { if (settingName === settingsNames.prompt) { return 'true'; @@ -872,22 +862,19 @@ describe('Cli', () => { return defaultValue; }); await cli.execute(rootFolder, ['cli', 'mock', 'optionsets']); - assert.strictEqual(promptStub.firstCall.args[0].choices[0], firstOptionValue); - assert.strictEqual(promptStub.firstCall.args[0].choices[1], secondOptionValue); - assert.strictEqual(promptStub.lastCall.args[0].message, `${firstOptionValue}:`); - assert(promptStub.calledTwice); + assert.strictEqual(promptStub.firstCall.args[0].choices[0].value, firstOptionValue); + assert.strictEqual(promptStub.firstCall.args[0].choices[1].value, secondOptionValue); + assert.strictEqual(promptInputStub.firstCall.args[0].message, `${firstOptionValue}:`); + assert(promptStub.calledOnce); + assert(promptInputStub.calledOnce); }); it(`prompts to choose which option you wish to use when multiple options in a specific optionset are specified`, async () => { let firstOptionValue = '', secondOptionValue = ''; - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake((opts: any, _) => { - if (opts.type === 'list' && opts.name === 'missingRequiredOptionName') { - firstOptionValue = opts.choices[0]; - secondOptionValue = opts.choices[1]; - return { missingRequiredOptionName: opts.choices[0] } as any; - } - - throw 'Specific prompt not found'; + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + firstOptionValue = (config.choices[0] as Choice).value; + secondOptionValue = (config.choices[1] as Choice).value; + return (config.choices[0] as Choice).value; }); sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { @@ -898,27 +885,21 @@ describe('Cli', () => { }); await cli.execute(rootFolder, ['cli', 'mock', 'optionsets', '--opt1', 'testvalue', '--opt2', 'testvalue']); assert.strictEqual(promptStub.lastCall.args[0].message, `Option to use:`); - assert.strictEqual(promptStub.lastCall.args[0].choices[0], firstOptionValue); - assert.strictEqual(promptStub.lastCall.args[0].choices[1], secondOptionValue); + assert.strictEqual(promptStub.lastCall.args[0].choices[0].value, firstOptionValue); + assert.strictEqual(promptStub.lastCall.args[0].choices[1].value, secondOptionValue); assert(promptStub.calledOnce); }); it(`prompts to choose runsWhen option from optionSet when dependant option is set and prompts for the value`, async () => { let firstOptionValue = '', secondOptionValue = ''; - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake((opts: any, _) => { - if (opts.type === 'list' && opts.name === 'missingRequiredOptionName') { - firstOptionValue = opts.choices[0]; - secondOptionValue = opts.choices[1]; - return { missingRequiredOptionName: opts.choices[0] } as any; - } - - if (opts.name === 'missingRequiredOptionValue') { - return { missingRequiredOptionValue: 'Test 123' } as any; - } - - throw 'Specific prompt not found'; + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + firstOptionValue = (config.choices[0] as Choice).value; + secondOptionValue = (config.choices[1] as Choice).value; + return (config.choices[0] as Choice).value; }); + const promptInputStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').resolves('Test 123'); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { if (settingName === settingsNames.prompt) { return 'true'; @@ -927,21 +908,18 @@ describe('Cli', () => { }); await cli.execute(rootFolder, ['cli', 'mock', 'optionsets', '--opt2', 'testvalue']); assert.strictEqual(promptStub.firstCall.args[0].message, `Option to use:`); - assert.strictEqual(promptStub.firstCall.args[0].choices[0], firstOptionValue); - assert.strictEqual(promptStub.firstCall.args[0].choices[1], secondOptionValue); - assert(promptStub.calledTwice); + assert.strictEqual(promptStub.firstCall.args[0].choices[0].value, firstOptionValue); + assert.strictEqual(promptStub.firstCall.args[0].choices[1].value, secondOptionValue); + assert(promptStub.calledOnce); + assert(promptInputStub.calledOnce); }); it(`prompts to pick one of the options from an optionSet when runsWhen condition is matched`, async () => { let firstOptionValue = '', secondOptionValue = ''; - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake((opts: any, _) => { - if (opts.type === 'list' && opts.name === 'missingRequiredOptionName') { - firstOptionValue = opts.choices[0]; - secondOptionValue = opts.choices[1]; - return { missingRequiredOptionName: opts.choices[0] } as any; - } - - throw 'Specific prompt not found'; + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forSelection').callsFake(async (config: SelectionConfig): Promise => { + firstOptionValue = (config.choices[0] as Choice).value; + secondOptionValue = (config.choices[1] as Choice).value; + return (config.choices[0] as Choice).value; }); sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { @@ -951,8 +929,8 @@ describe('Cli', () => { return defaultValue; }); await cli.execute(rootFolder, ['cli', 'mock', 'optionsets', '--opt2', 'testvalue', '--opt3', 'opt 3', '--opt4', 'opt 4']); - assert.strictEqual(promptStub.lastCall.args[0].choices[0], firstOptionValue); - assert.strictEqual(promptStub.lastCall.args[0].choices[1], secondOptionValue); + assert.strictEqual(promptStub.lastCall.args[0].choices[0].value, firstOptionValue); + assert.strictEqual(promptStub.lastCall.args[0].choices[1].value, secondOptionValue); assert(promptStub.calledOnce); }); @@ -1075,8 +1053,8 @@ describe('Cli', () => { }, e => done(e)); }); - it('calls inquirer when command shows prompt', (done) => { - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake(() => Promise.resolve() as any); + it('calls prompt tool when command shows prompt', (done) => { + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forConfirmation').resolves(true); const mockCommandWithPrompt = new MockCommandWithPrompt(); Cli @@ -1224,8 +1202,8 @@ describe('Cli', () => { }, e => done(e)); }); - it('calls inquirer when command shows prompt and executed with output', (done) => { - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake(() => Promise.resolve() as any); + it('calls prompt tool when command shows prompt and executed with output', (done) => { + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forConfirmation').resolves(true); const mockCommandWithPrompt = new MockCommandWithPrompt(); Cli @@ -1241,9 +1219,10 @@ describe('Cli', () => { }, e => done(e)); }); - it('calls inquirer when command shows interactive prompt and executed with output', async () => { + it('calls prompt tool when command shows interactive prompt and executed with output', async () => { sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((() => true)); - const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forInput').callsFake(() => Promise.resolve({ select: '1' })); + + const promptStub: sinon.SinonStub = sinon.stub(prompt, 'forSelection').callsFake(() => Promise.resolve("test") as any); const mockCommandWithHandleMultipleResultsFound = new MockCommandWithHandleMultipleResultsFound(); await Cli.executeCommandWithOutput(mockCommandWithHandleMultipleResultsFound, { options: { _: [] } }); diff --git a/src/cli/Cli.ts b/src/cli/Cli.ts index 3ea85c4a3bb..ce423946646 100644 --- a/src/cli/Cli.ts +++ b/src/cli/Cli.ts @@ -20,7 +20,7 @@ import { validation } from '../utils/validation.js'; import { CommandInfo } from './CommandInfo.js'; import { CommandOptionInfo } from './CommandOptionInfo.js'; import { Logger } from './Logger.js'; -import { prompt } from '../utils/prompt.js'; +import { SelectionConfig, ConfirmationConfig, prompt } from '../utils/prompt.js'; export interface CommandOutput { stdout: string; @@ -967,7 +967,7 @@ export class Cli { } } - public static async prompt(options: any, answers?: any): Promise { + public static async promptForSelection(config: SelectionConfig): Promise { const cli = Cli.getInstance(); const spinnerSpinning = cli.spinner.isSpinning; @@ -976,7 +976,8 @@ export class Cli { cli.spinner.stop(); } - const response = await prompt.forInput(options, answers) as T; + const answer = await prompt.forSelection(config); + Cli.error(''); // Restart the spinner if it was running before the prompt /* c8 ignore next 3 */ @@ -984,7 +985,49 @@ export class Cli { cli.spinner.start(); } - return response; + return answer; + } + + public static async promptForConfirmation(config: ConfirmationConfig): Promise { + const cli = Cli.getInstance(); + const spinnerSpinning = cli.spinner.isSpinning; + + /* c8 ignore next 3 */ + if (spinnerSpinning) { + cli.spinner.stop(); + } + + const answer = await prompt.forConfirmation(config); + Cli.error(''); + + // Restart the spinner if it was running before the prompt + /* c8 ignore next 3 */ + if (spinnerSpinning) { + cli.spinner.start(); + } + + return answer; + } + + // Obsolete, will be removed after rebase soon + /* c8 ignore next 18 */ + public static async prompt(options: any): Promise { + const cli = Cli.getInstance(); + const spinnerSpinning = cli.spinner.isSpinning; + + if (spinnerSpinning) { + cli.spinner.stop(); + } + + const answer = await prompt.forConfirmation(options.message); + Cli.error(''); + + // Restart the spinner if it was running before the prompt + if (spinnerSpinning) { + cli.spinner.start(); + } + + return { continue: answer } as T; } public static async handleMultipleResultsFound(message: string, values: { [key: string]: T }): Promise { @@ -993,16 +1036,11 @@ export class Cli { throw new Error(`${message} Found: ${Object.keys(values).join(', ')}.`); } - const response = await Cli.prompt<{ select: string }>({ - type: 'list', - name: 'select', - default: 0, - prefix: '🌶️ ', - message: `${message} Please choose one:`, - choices: Object.keys(values) - }); + Cli.error(`🌶️ ${message}`); + const choices = Object.keys(values).map((choice: any) => { return { name: choice, value: choice }; }); + const response = await Cli.promptForSelection({ message: `Please choose one:`, choices }); - return values[response.select]; + return values[response]; } private static removeShortOptions(args: { options: minimist.ParsedArgs }): { options: minimist.ParsedArgs } { diff --git a/src/m365/aad/commands/app/app-remove.spec.ts b/src/m365/aad/commands/app/app-remove.spec.ts index b0adb2ae0fa..2aa28fe8952 100644 --- a/src/m365/aad/commands/app/app-remove.spec.ts +++ b/src/m365/aad/commands/app/app-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; let deleteRequestStub: sinon.SinonStub; before(() => { @@ -45,12 +45,12 @@ describe(commands.APP_REMOVE, () => { } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); @@ -83,7 +83,7 @@ describe(commands.APP_REMOVE, () => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); @@ -142,25 +142,19 @@ describe(commands.APP_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the app when confirm option not passed', async () => { + it('prompts before removing the app when force option not passed', async () => { await command.action(logger, { options: { appId: 'd75be2e1-0204-4f95-857d-51a37cf40be8' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); }); it('aborts removing the app when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -171,8 +165,8 @@ describe(commands.APP_REMOVE, () => { }); it('deletes app when prompt confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/aad/commands/app/app-remove.ts b/src/m365/aad/commands/app/app-remove.ts index 127fca8d103..fe0ca9415ff 100644 --- a/src/m365/aad/commands/app/app-remove.ts +++ b/src/m365/aad/commands/app/app-remove.ts @@ -104,14 +104,9 @@ class AadAppRemoveCommand extends GraphCommand { await deleteApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the app?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the app?` }); - if (result.continue) { + if (result) { await deleteApp(); } } diff --git a/src/m365/aad/commands/app/app-role-remove.spec.ts b/src/m365/aad/commands/app/app-role-remove.spec.ts index 79ee6150fe9..5a4fef802e9 100644 --- a/src/m365/aad/commands/app/app-role-remove.spec.ts +++ b/src/m365/aad/commands/app/app-role-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_ROLE_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -43,11 +43,12 @@ describe(commands.APP_ROLE_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -55,7 +56,7 @@ describe(commands.APP_ROLE_REMOVE, () => { sinonUtil.restore([ request.get, request.patch, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); @@ -1413,7 +1414,7 @@ describe(commands.APP_ROLE_REMOVE, () => { assert(removeRequestIssued); }); - it('handles when multiple roles with the same name are found and --confirm option specified', async () => { + it('handles when multiple roles with the same name are found and --force option specified', async () => { const getRequestStub = sinon.stub(request, 'get'); getRequestStub.onFirstCall().callsFake(async opts => { @@ -1684,32 +1685,22 @@ describe(commands.APP_ROLE_REMOVE, () => { }), new CommandError(`No app role with id 'c4352a0a-494f-46f9-b843-479855c173a7' found.`)); }); - it('prompts before removing the specified app role when confirm option not passed', async () => { + it('prompts before removing the specified app role when force option not passed', async () => { await command.action(logger, { options: { appName: 'App-Name', claim: 'Product.Read' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified app role when confirm option not passed (debug)', async () => { + it('prompts before removing the specified app role when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, appName: 'App-Name', claim: 'Product.Read' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('deletes an app role when the role is in enabled state and valid appObjectId, role claim and the prompt is confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); @@ -1789,8 +1780,8 @@ describe(commands.APP_ROLE_REMOVE, () => { it('deletes an app role when the role is in enabled state and valid appId, role name and prompt is confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); @@ -1883,8 +1874,8 @@ describe(commands.APP_ROLE_REMOVE, () => { it('deletes an app role when the role is in enabled state and valid appId, role id and prompt is confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); @@ -1978,8 +1969,8 @@ describe(commands.APP_ROLE_REMOVE, () => { it('aborts deleting app role when prompt is not confirmed', async () => { // represents the aad app get request called when the prompt is confirmed const patchStub = sinon.stub(request, 'get'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { appName: 'App-Name', claim: 'Product.Read' } }); assert(patchStub.notCalled); @@ -1988,8 +1979,8 @@ describe(commands.APP_ROLE_REMOVE, () => { it('aborts deleting app role when prompt is not confirmed (debug)', async () => { // represents the aad app get request called when the prompt is confirmed const patchStub = sinon.stub(request, 'get'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); command.action(logger, { options: { debug: true, appName: 'App-Name', claim: 'Product.Read' } }); assert(patchStub.notCalled); diff --git a/src/m365/aad/commands/app/app-role-remove.ts b/src/m365/aad/commands/app/app-role-remove.ts index 19bd848cacd..1bd1beaae44 100644 --- a/src/m365/aad/commands/app/app-role-remove.ts +++ b/src/m365/aad/commands/app/app-role-remove.ts @@ -99,14 +99,9 @@ class AadAppRoleRemoveCommand extends GraphCommand { await deleteAppRole(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the app role ?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the app role ?` }); - if (result.continue) { + if (result) { await deleteAppRole(); } } diff --git a/src/m365/aad/commands/approleassignment/approleassignment-remove.spec.ts b/src/m365/aad/commands/approleassignment/approleassignment-remove.spec.ts index dcc63ad56fe..2b19fc13a77 100644 --- a/src/m365/aad/commands/approleassignment/approleassignment-remove.spec.ts +++ b/src/m365/aad/commands/approleassignment/approleassignment-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.APPROLEASSIGNMENT_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; let deleteRequestStub: sinon.SinonStub; before(() => { @@ -45,11 +45,12 @@ describe(commands.APPROLEASSIGNMENT_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); sinon.stub(request, 'get').callsFake(async (opts: any) => { if ((opts.url as string).indexOf(`/v1.0/servicePrincipals?`) > -1) { @@ -75,7 +76,7 @@ describe(commands.APPROLEASSIGNMENT_REMOVE, () => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -93,39 +94,29 @@ describe(commands.APPROLEASSIGNMENT_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the app role assignment when confirm option not passed', async () => { - await command.action(logger, { options: { appId: 'dc311e81-e099-4c64-bd66-c7183465f3f2', resource: 'SharePoint', scopes: 'Sites.Read.All' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + it('prompts before removing the app role assignment when force option not passed', async () => { + await command.action(logger, { options: { appId: 'dc311e81-e099-4c64-bd66-c7183465f3f2', resource: 'SharePoint', scope: 'Sites.Read.All' } }); assert(promptIssued); }); - it('prompts before removing the app role assignment when confirm option not passed (debug)', async () => { - await command.action(logger, { options: { debug: true, appId: 'dc311e81-e099-4c64-bd66-c7183465f3f2', resource: 'SharePoint', scopes: 'Sites.Read.All' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + it('prompts before removing the app role assignment when force option not passed (debug)', async () => { + await command.action(logger, { options: { debug: true, appId: 'dc311e81-e099-4c64-bd66-c7183465f3f2', resource: 'SharePoint', scope: 'Sites.Read.All' } }); assert(promptIssued); }); it('aborts removing the app role assignment when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { appDisplayName: 'myapp', resource: 'SharePoint', scopes: 'Sites.Read.All' } }); assert(deleteRequestStub.notCalled); }); it('deletes app role assignment when prompt confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, appDisplayName: 'myapp', resource: 'SharePoint', scopes: 'Sites.Read.All' } }); assert(deleteRequestStub.called); diff --git a/src/m365/aad/commands/approleassignment/approleassignment-remove.ts b/src/m365/aad/commands/approleassignment/approleassignment-remove.ts index 3f3380b5fba..646dfe77e41 100644 --- a/src/m365/aad/commands/approleassignment/approleassignment-remove.ts +++ b/src/m365/aad/commands/approleassignment/approleassignment-remove.ts @@ -197,15 +197,9 @@ class AadAppRoleAssignmentRemoveCommand extends GraphCommand { await removeAppRoleAssignment(); } else { - const result = await Cli.prompt<{ continue: boolean }>( - { - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the appRoleAssignment with scopes ${args.options.scopes} for resource ${args.options.resource}?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the appRoleAssignment with scope ${args.options.scope} for resource ${args.options.resource}?` }); + + if (result) { await removeAppRoleAssignment(); } } diff --git a/src/m365/aad/commands/group/group-remove.spec.ts b/src/m365/aad/commands/group/group-remove.spec.ts index a64aecf1e37..4f635be6b00 100644 --- a/src/m365/aad/commands/group/group-remove.spec.ts +++ b/src/m365/aad/commands/group/group-remove.spec.ts @@ -21,7 +21,6 @@ describe(commands.GROUP_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -45,18 +44,13 @@ describe(commands.GROUP_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; - }); - promptOptions = undefined; }); afterEach(() => { sinonUtil.restore([ request.delete, aadGroup.getGroupIdByDisplayName, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -86,7 +80,9 @@ describe(commands.GROUP_REMOVE, () => { assert(deleteRequestStub.called); }); - it('removes the specified group by displayName while prompting for confirmation', async () => { + it('removes the specified group by displayName when passing the force option', async () => { + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(true); + sinon.stub(aadGroup, 'getGroupIdByDisplayName').resolves(groupId); const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => { @@ -97,14 +93,32 @@ describe(commands.GROUP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + await command.action(logger, { options: { verbose: true, displayName: displayName, force: true } }); + assert(deleteRequestStub.called); + assert(confirmationStub.notCalled); + }); + + it('removes the specified group by displayName while prompting for confirmation', async () => { + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(true); + + sinon.stub(aadGroup, 'getGroupIdByDisplayName').resolves(groupId); + + const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/groups/${groupId}`) { + return; + } + + throw 'Invalid request'; + }); await command.action(logger, { options: { verbose: true, displayName: displayName } }); assert(deleteRequestStub.called); + assert(confirmationStub.calledOnce); }); it('throws an error when group by id cannot be found', async () => { + sinon.stub(Cli, 'promptForConfirmation').resolves(true); + const error = { error: { code: 'Request_ResourceNotFound', @@ -129,17 +143,16 @@ describe(commands.GROUP_REMOVE, () => { }); it('prompts before removing the specified group when confirm option not passed', async () => { - await command.action(logger, { options: { id: groupId } }); - let promptIssued = false; + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + await command.action(logger, { options: { id: groupId } }); - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('aborts removing group when prompt not confirmed', async () => { + sinon.stub(Cli, 'promptForConfirmation').resolves(false); + const deleteSpy = sinon.stub(request, 'delete').resolves(); await command.action(logger, { options: { id: groupId } }); diff --git a/src/m365/aad/commands/group/group-remove.ts b/src/m365/aad/commands/group/group-remove.ts index 49d87139f19..83746c46cbc 100644 --- a/src/m365/aad/commands/group/group-remove.ts +++ b/src/m365/aad/commands/group/group-remove.ts @@ -115,14 +115,9 @@ class AadGroupRemoveCommand extends GraphCommand { await removeGroup(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove group '${args.options.id || args.options.displayName}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove group '${args.options.id || args.options.displayName}'?` }); - if (result.continue) { + if (result) { await removeGroup(); } } diff --git a/src/m365/aad/commands/groupsetting/groupsetting-remove.spec.ts b/src/m365/aad/commands/groupsetting/groupsetting-remove.spec.ts index 4e8c9f4bf29..6789fe3f53e 100644 --- a/src/m365/aad/commands/groupsetting/groupsetting-remove.spec.ts +++ b/src/m365/aad/commands/groupsetting/groupsetting-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,18 +43,19 @@ describe(commands.GROUPSETTING_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, global.setTimeout, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -71,7 +72,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('removes the specified group setting without prompting for confirmation when confirm option specified', async () => { + it('removes the specified group setting without prompting for confirmation when force option specified', async () => { const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === 'https://graph.microsoft.com/v1.0/groupSettings/28beab62-7540-4db1-a23f-29a6018a3848') { return; @@ -84,7 +85,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { assert(deleteRequestStub.called); }); - it('removes the specified group setting without prompting for confirmation when confirm option specified (debug)', async () => { + it('removes the specified group setting without prompting for confirmation when force option specified (debug)', async () => { const deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === 'https://graph.microsoft.com/v1.0/groupSettings/28beab62-7540-4db1-a23f-29a6018a3848') { return; @@ -97,24 +98,14 @@ describe(commands.GROUPSETTING_REMOVE, () => { assert(deleteRequestStub.called); }); - it('prompts before removing the specified group setting when confirm option not passed', async () => { + it('prompts before removing the specified group setting when force option not passed', async () => { await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified group setting when confirm option not passed (debug)', async () => { + it('prompts before removing the specified group setting when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -136,8 +127,8 @@ describe(commands.GROUPSETTING_REMOVE, () => { it('removes the group setting when prompt confirmed', async () => { const postStub = sinon.stub(request, 'delete').callsFake(() => Promise.resolve()); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(postStub.called); @@ -146,8 +137,8 @@ describe(commands.GROUPSETTING_REMOVE, () => { it('removes the group setting when prompt confirmed (debug)', async () => { const deleteStub = sinon.stub(request, 'delete').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(deleteStub.called); diff --git a/src/m365/aad/commands/groupsetting/groupsetting-remove.ts b/src/m365/aad/commands/groupsetting/groupsetting-remove.ts index 3de97016bb0..5ea85a377b3 100644 --- a/src/m365/aad/commands/groupsetting/groupsetting-remove.ts +++ b/src/m365/aad/commands/groupsetting/groupsetting-remove.ts @@ -88,14 +88,9 @@ class AadGroupSettingRemoveCommand extends GraphCommand { await removeGroupSetting(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the group setting ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the group setting ${args.options.id}?` }); - if (result.continue) { + if (result) { await removeGroupSetting(); } } diff --git a/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.spec.ts b/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.spec.ts index c5ecfec4098..ae4e6106af1 100644 --- a/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.spec.ts +++ b/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.spec.ts @@ -16,7 +16,7 @@ import command from './m365group-recyclebinitem-clear.js'; describe(commands.M365GROUP_RECYCLEBINITEM_CLEAR, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -40,18 +40,19 @@ describe(commands.M365GROUP_RECYCLEBINITEM_CLEAR, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -256,31 +257,22 @@ describe(commands.M365GROUP_RECYCLEBINITEM_CLEAR, () => { it('prompts before clearing the M365 Group recycle bin items when --force option is not passed', async () => { await command.action(logger, { options: {} }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts clearing the M365 Group recyclebin items when prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); assert(deleteSpy.notCalled); }); it('aborts clearing the recycle bin items when prompt not confirmed (debug)', async () => { const deleteSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true } }); assert(deleteSpy.notCalled); }); @@ -349,10 +341,8 @@ describe(commands.M365GROUP_RECYCLEBINITEM_CLEAR, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: {} }); assert(deleteStub.calledTwice); }); @@ -447,10 +437,8 @@ describe(commands.M365GROUP_RECYCLEBINITEM_CLEAR, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true } }); assert(deleteStub.calledThrice); }); diff --git a/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.ts b/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.ts index 50f9ac53af1..b0fe93ed4ac 100644 --- a/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.ts +++ b/src/m365/aad/commands/m365group/m365group-recyclebinitem-clear.ts @@ -61,14 +61,9 @@ class AadM365GroupRecycleBinItemClearCommand extends GraphCommand { await clearM365GroupRecycleBinItems(); } else { - const response = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to clear all M365 Groups from recycle bin ?` - }); + const response = await Cli.promptForConfirmation({ message: `Are you sure you want to clear all M365 Groups from recycle bin ?` }); - if (response.continue) { + if (response) { await clearM365GroupRecycleBinItems(); } } diff --git a/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.spec.ts b/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.spec.ts index 9d84ef5b40b..43cc018c920 100644 --- a/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.spec.ts +++ b/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.spec.ts @@ -59,7 +59,7 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -68,6 +68,13 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -83,18 +90,19 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -129,22 +137,17 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified group when confirm option not passed with id', async () => { + it('prompts before removing the specified group when force option not passed with id', async () => { await command.action(logger, { options: { id: validGroupId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified group when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified group when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -210,9 +213,9 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { sinon.stub(Cli, 'handleMultipleResultsFound').resolves(singleGroupsResponse.value[0]); - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -247,8 +250,8 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -272,8 +275,8 @@ describe(commands.M365GROUP_RECYCLEBINITEM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.ts b/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.ts index a6305a83242..5694c7c5119 100644 --- a/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.ts +++ b/src/m365/aad/commands/m365group/m365group-recyclebinitem-remove.ts @@ -105,14 +105,9 @@ class AadM365GroupRecycleBinItemRemoveCommand extends GraphCommand { await removeGroup(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the group '${args.options.id || args.options.displayName || args.options.mailNickname}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the group '${args.options.id || args.options.displayName || args.options.mailNickname}'?` }); - if (result.continue) { + if (result) { await removeGroup(); } } diff --git a/src/m365/aad/commands/m365group/m365group-recyclebinitem-restore.spec.ts b/src/m365/aad/commands/m365group/m365group-recyclebinitem-restore.spec.ts index 6b8214ca6af..0d632842b8f 100644 --- a/src/m365/aad/commands/m365group/m365group-recyclebinitem-restore.spec.ts +++ b/src/m365/aad/commands/m365group/m365group-recyclebinitem-restore.spec.ts @@ -67,6 +67,13 @@ describe(commands.M365GROUP_RECYCLEBINITEM_RESTORE, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/aad/commands/m365group/m365group-remove.spec.ts b/src/m365/aad/commands/m365group/m365group-remove.spec.ts index 02b7b6446c2..49a0d4dc6b6 100644 --- a/src/m365/aad/commands/m365group/m365group-remove.spec.ts +++ b/src/m365/aad/commands/m365group/m365group-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.M365GROUP_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -42,19 +42,20 @@ describe(commands.M365GROUP_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; loggerLogSpy = sinon.spy(logger, 'log'); - promptOptions = undefined; }); afterEach(() => { sinonUtil.restore([ request.delete, global.setTimeout, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -71,7 +72,7 @@ describe(commands.M365GROUP_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('removes the specified group without prompting for confirmation when confirm option specified', async () => { + it('removes the specified group without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === 'https://graph.microsoft.com/v1.0/groups/28beab62-7540-4db1-a23f-29a6018a3848') { return; @@ -84,7 +85,7 @@ describe(commands.M365GROUP_REMOVE, () => { assert(loggerLogSpy.notCalled); }); - it('removes the specified group without prompting for confirmation when confirm option specified (debug)', async () => { + it('removes the specified group without prompting for confirmation when force option specified (debug)', async () => { sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === 'https://graph.microsoft.com/v1.0/groups/28beab62-7540-4db1-a23f-29a6018a3848') { return; @@ -97,32 +98,22 @@ describe(commands.M365GROUP_REMOVE, () => { assert(loggerLogSpy.notCalled); }); - it('prompts before removing the specified group when confirm option not passed', async () => { + it('prompts before removing the specified group when force option not passed', async () => { await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified group when confirm option not passed (debug)', async () => { + it('prompts before removing the specified group when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing the group when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(postSpy.notCalled); @@ -130,8 +121,8 @@ describe(commands.M365GROUP_REMOVE, () => { it('aborts removing the group when prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(postSpy.notCalled); @@ -139,18 +130,16 @@ describe(commands.M365GROUP_REMOVE, () => { it('removes the group when prompt confirmed', async () => { const postStub = sinon.stub(request, 'delete').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(postStub.called); }); it('removes the group when prompt confirmed (debug)', async () => { const postStub = sinon.stub(request, 'delete').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); assert(postStub.called); @@ -170,14 +159,14 @@ describe(commands.M365GROUP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848', skipRecycleBin: true } }); assert(groupPermDeleteCallIssued); }); - it('removes the group permanently when with confirm option', async () => { + it('removes the group permanently when with force option', async () => { let groupPermDeleteCallIssued = false; sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/groups/28beab62-7540-4db1-a23f-29a6018a3848`) { diff --git a/src/m365/aad/commands/m365group/m365group-remove.ts b/src/m365/aad/commands/m365group/m365group-remove.ts index 6bea32c609b..dab26350e6d 100644 --- a/src/m365/aad/commands/m365group/m365group-remove.ts +++ b/src/m365/aad/commands/m365group/m365group-remove.ts @@ -103,14 +103,9 @@ class AadM365GroupRemoveCommand extends GraphCommand { await removeGroup(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the group ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the group ${args.options.id}?` }); - if (result.continue) { + if (result) { await removeGroup(); } } diff --git a/src/m365/aad/commands/m365group/m365group-user-remove.spec.ts b/src/m365/aad/commands/m365group/m365group-user-remove.spec.ts index 83a4a68c4a4..24a830aac83 100644 --- a/src/m365/aad/commands/m365group/m365group-user-remove.spec.ts +++ b/src/m365/aad/commands/m365group/m365group-user-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.M365GROUP_USER_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -44,11 +44,12 @@ describe(commands.M365GROUP_USER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -57,7 +58,7 @@ describe(commands.M365GROUP_USER_REMOVE, () => { request.get, request.delete, global.setTimeout, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -135,41 +136,31 @@ describe(commands.M365GROUP_USER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified user from the specified Microsoft 365 Group when confirm option not passed', async () => { + it('prompts before removing the specified user from the specified Microsoft 365 Group when force option not passed', async () => { await command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified user from the specified Team when confirm option not passed (debug)', async () => { + it('prompts before removing the specified user from the specified Team when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, teamId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified user from the specified Microsoft 365 Group when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified user from the specified Microsoft 365 Group when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } }); assert(postSpy.notCalled); }); - it('aborts removing the specified user from the specified Microsoft 365 Group when confirm option not passed and prompt not confirmed (debug)', async () => { + it('aborts removing the specified user from the specified Microsoft 365 Group when force option not passed and prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } }); assert(postSpy.notCalled); @@ -217,8 +208,8 @@ describe(commands.M365GROUP_USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } }); assert(memberDeleteCallIssued); @@ -493,10 +484,8 @@ describe(commands.M365GROUP_USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } } as any), new CommandError('Invalid object identifier')); }); @@ -538,8 +527,8 @@ describe(commands.M365GROUP_USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } } as any), new CommandError('Invalid object identifier')); @@ -592,8 +581,8 @@ describe(commands.M365GROUP_USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } } as any), new CommandError('Invalid object identifier')); @@ -610,8 +599,8 @@ describe(commands.M365GROUP_USER_REMOVE, () => { sinon.stub(request, 'delete').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { debug: true, groupId: "00000000-0000-0000-0000-000000000000", userName: "anne.matthews@contoso.onmicrosoft.com" } } as any), new CommandError("Invalid request")); }); diff --git a/src/m365/aad/commands/m365group/m365group-user-remove.ts b/src/m365/aad/commands/m365group/m365group-user-remove.ts index f89d1b099ba..9367547c678 100644 --- a/src/m365/aad/commands/m365group/m365group-user-remove.ts +++ b/src/m365/aad/commands/m365group/m365group-user-remove.ts @@ -155,14 +155,9 @@ class AadM365GroupUserRemoveCommand extends GraphCommand { await removeUser(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove ${args.options.userName} from the ${(typeof args.options.groupId !== 'undefined' ? 'group' : 'team')} ${groupId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove ${args.options.userName} from the ${(typeof args.options.groupId !== 'undefined' ? 'group' : 'team')} ${groupId}?` }); - if (result.continue) { + if (result) { await removeUser(); } } diff --git a/src/m365/aad/commands/oauth2grant/oauth2grant-remove.spec.ts b/src/m365/aad/commands/oauth2grant/oauth2grant-remove.spec.ts index 1a2827a35d1..ae03f8d3ed8 100644 --- a/src/m365/aad/commands/oauth2grant/oauth2grant-remove.spec.ts +++ b/src/m365/aad/commands/oauth2grant/oauth2grant-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -40,11 +40,12 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); }); @@ -52,7 +53,7 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -78,8 +79,8 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); assert(loggerLogToStderrSpy.called); @@ -95,8 +96,8 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); assert(loggerLogSpy.notCalled); @@ -117,24 +118,14 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { assert(deleteRequestStub.called); }); - it('prompts before removing OAuth2 permission grant when confirm option not passed', async () => { + it('prompts before removing OAuth2 permission grant when force option not passed', async () => { await command.action(logger, { options: { grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing OAuth2 permission grant when confirm option not passed (debug)', async () => { + it('prompts before removing OAuth2 permission grant when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -142,10 +133,8 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { it('aborts removing OAuth2 permission grant when prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); assert(deleteSpy.notCalled); @@ -154,8 +143,8 @@ describe(commands.OAUTH2GRANT_REMOVE, () => { it('aborts removing OAuth2 permission grant when prompt not confirmed (debug)', async () => { const deleteSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, grantId: 'YgA60KYa4UOPSdc-lpxYEnQkr8KVLDpCsOXkiV8i-ek' } }); assert(deleteSpy.notCalled); diff --git a/src/m365/aad/commands/oauth2grant/oauth2grant-remove.ts b/src/m365/aad/commands/oauth2grant/oauth2grant-remove.ts index df276dab9e5..175238ba5ca 100644 --- a/src/m365/aad/commands/oauth2grant/oauth2grant-remove.ts +++ b/src/m365/aad/commands/oauth2grant/oauth2grant-remove.ts @@ -66,14 +66,9 @@ class AadOAuth2GrantRemoveCommand extends GraphCommand { await removeOauth2Grant(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the OAuth2 permissions for ${args.options.grantId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the OAuth2 permissions for ${args.options.grantId}?` }); - if (result.continue) { + if (result) { await removeOauth2Grant(); } } diff --git a/src/m365/aad/commands/siteclassification/siteclassification-disable.spec.ts b/src/m365/aad/commands/siteclassification/siteclassification-disable.spec.ts index 4bec104e569..3879bd10b8f 100644 --- a/src/m365/aad/commands/siteclassification/siteclassification-disable.spec.ts +++ b/src/m365/aad/commands/siteclassification/siteclassification-disable.spec.ts @@ -15,7 +15,7 @@ import command from './siteclassification-disable.js'; describe(commands.SITECLASSIFICATION_DISABLE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -38,18 +38,19 @@ describe(commands.SITECLASSIFICATION_DISABLE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -67,13 +68,8 @@ describe(commands.SITECLASSIFICATION_DISABLE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before disabling siteclassification when confirm option not passed', async () => { + it('prompts before disabling siteclassification when force option not passed', async () => { await command.action(logger, { options: {} }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -488,8 +484,8 @@ describe(commands.SITECLASSIFICATION_DISABLE, () => { it('aborts removing the group when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); assert(postSpy.notCalled); @@ -577,8 +573,8 @@ describe(commands.SITECLASSIFICATION_DISABLE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: {} }); assert(deleteRequestIssued); diff --git a/src/m365/aad/commands/siteclassification/siteclassification-disable.ts b/src/m365/aad/commands/siteclassification/siteclassification-disable.ts index 0b44197f7e0..dde63733306 100644 --- a/src/m365/aad/commands/siteclassification/siteclassification-disable.ts +++ b/src/m365/aad/commands/siteclassification/siteclassification-disable.ts @@ -95,14 +95,9 @@ class AadSiteClassificationDisableCommand extends GraphCommand { await disableSiteClassification(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to disable site classification?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to disable site classification?` }); - if (result.continue) { + if (result) { await disableSiteClassification(); } } diff --git a/src/m365/aad/commands/user/user-license-remove.spec.ts b/src/m365/aad/commands/user/user-license-remove.spec.ts index 94e9e2388da..d0b0602c2da 100644 --- a/src/m365/aad/commands/user/user-license-remove.spec.ts +++ b/src/m365/aad/commands/user/user-license-remove.spec.ts @@ -24,7 +24,7 @@ describe(commands.USER_LICENSE_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -48,17 +48,18 @@ describe(commands.USER_LICENSE_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -112,26 +113,21 @@ describe(commands.USER_LICENSE_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified user licenses when confirm option not passed', async () => { + it('prompts before removing the specified user licenses when force option not passed', async () => { await command.action(logger, { options: { ids: validIds, userId: validUserId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified user licenses when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified user licenses when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -164,8 +160,8 @@ describe(commands.USER_LICENSE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/aad/commands/user/user-license-remove.ts b/src/m365/aad/commands/user/user-license-remove.ts index d744d188945..80726c660d3 100644 --- a/src/m365/aad/commands/user/user-license-remove.ts +++ b/src/m365/aad/commands/user/user-license-remove.ts @@ -98,14 +98,9 @@ class AadUserLicenseRemoveCommand extends GraphCommand { await this.deleteUserLicenses(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the licenses for the user '${args.options.userId || args.options.userName}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the licenses for the user '${args.options.userId || args.options.userName}'?` }); - if (result.continue) { + if (result) { await this.deleteUserLicenses(args); } } diff --git a/src/m365/aad/commands/user/user-recyclebinitem-clear.spec.ts b/src/m365/aad/commands/user/user-recyclebinitem-clear.spec.ts index a5be2d7ec71..06cfba08993 100644 --- a/src/m365/aad/commands/user/user-recyclebinitem-clear.spec.ts +++ b/src/m365/aad/commands/user/user-recyclebinitem-clear.spec.ts @@ -16,7 +16,7 @@ import command from './user-recyclebinitem-clear.js'; describe(commands.USER_RECYCLEBINITEM_CLEAR, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; const deletedUsersResponse = [{ id: '4c099956-ca9a-4e60-ad5f-3f8447122706' }]; const graphGetUrl = 'https://graph.microsoft.com/v1.0/directory/deletedItems/microsoft.graph.user?$select=id'; @@ -43,11 +43,12 @@ describe(commands.USER_RECYCLEBINITEM_CLEAR, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; (command as any).items = []; }); @@ -55,7 +56,7 @@ describe(commands.USER_RECYCLEBINITEM_CLEAR, () => { sinonUtil.restore([ request.post, odata.getAllItems, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -75,8 +76,8 @@ describe(commands.USER_RECYCLEBINITEM_CLEAR, () => { it('removes a single user when prompt confirmed', async () => { let amountOfBatches = 0; - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(odata, 'getAllItems').callsFake(async (url) => { if (url === graphGetUrl) { @@ -124,17 +125,12 @@ describe(commands.USER_RECYCLEBINITEM_CLEAR, () => { it('prompts before removing users', async () => { await command.action(logger, { options: {} }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing users when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); const postStub = sinon.stub(request, 'post').callsFake(async () => { return; }); diff --git a/src/m365/aad/commands/user/user-recyclebinitem-clear.ts b/src/m365/aad/commands/user/user-recyclebinitem-clear.ts index b21760348d5..81a73efca2d 100644 --- a/src/m365/aad/commands/user/user-recyclebinitem-clear.ts +++ b/src/m365/aad/commands/user/user-recyclebinitem-clear.ts @@ -90,14 +90,9 @@ class AadUserRecycleBinItemClearCommand extends GraphCommand { await clearRecycleBinUsers(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: 'Are you sure you want to permanently delete all deleted users?' - }); + const result = await Cli.promptForConfirmation({ message: 'Are you sure you want to permanently delete all deleted users?' }); - if (result.continue) { + if (result) { await clearRecycleBinUsers(); } } diff --git a/src/m365/aad/commands/user/user-recyclebinitem-remove.spec.ts b/src/m365/aad/commands/user/user-recyclebinitem-remove.spec.ts index 9dc61f28a11..d35c3c9fb42 100644 --- a/src/m365/aad/commands/user/user-recyclebinitem-remove.spec.ts +++ b/src/m365/aad/commands/user/user-recyclebinitem-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.USER_RECYCLEBINITEM_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -43,18 +43,19 @@ describe(commands.USER_RECYCLEBINITEM_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; (command as any).items = []; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -72,8 +73,8 @@ describe(commands.USER_RECYCLEBINITEM_REMOVE, () => { }); it('removes the user when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const deleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/directory/deletedItems/${validUserId}`) { @@ -100,17 +101,12 @@ describe(commands.USER_RECYCLEBINITEM_REMOVE, () => { it('prompts before removing user', async () => { await command.action(logger, { options: { id: validUserId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing users when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); const deleteStub = sinon.stub(request, 'delete').resolves(); await command.action(logger, { options: { id: validUserId } }); diff --git a/src/m365/aad/commands/user/user-recyclebinitem-remove.ts b/src/m365/aad/commands/user/user-recyclebinitem-remove.ts index 8b3c8d69001..591cfc099dc 100644 --- a/src/m365/aad/commands/user/user-recyclebinitem-remove.ts +++ b/src/m365/aad/commands/user/user-recyclebinitem-remove.ts @@ -85,14 +85,9 @@ class AadUserRecycleBinItemRemoveCommand extends GraphCommand { await clearRecycleBinItem(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to permanently delete the user with id ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to permanently delete the user with id ${args.options.id}?` }); - if (result.continue) { + if (result) { await clearRecycleBinItem(); } } diff --git a/src/m365/aad/commands/user/user-remove.spec.ts b/src/m365/aad/commands/user/user-remove.spec.ts index 8f62a718fa2..85bc5b525bb 100644 --- a/src/m365/aad/commands/user/user-remove.spec.ts +++ b/src/m365/aad/commands/user/user-remove.spec.ts @@ -22,7 +22,7 @@ describe(commands.USER_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -46,17 +46,18 @@ describe(commands.USER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -101,22 +102,17 @@ describe(commands.USER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified user when confirm option not passed', async () => { + it('prompts before removing the specified user when force option not passed', async () => { await command.action(logger, { options: { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified user when force option not passed and prompt not confirmed', async () => { const deleteStub = sinon.stub(request, 'delete').resolves(); await command.action(logger, { @@ -136,8 +132,8 @@ describe(commands.USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -157,8 +153,8 @@ describe(commands.USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/aad/commands/user/user-remove.ts b/src/m365/aad/commands/user/user-remove.ts index ea67a7c989a..d59a6af3b4c 100644 --- a/src/m365/aad/commands/user/user-remove.ts +++ b/src/m365/aad/commands/user/user-remove.ts @@ -90,14 +90,9 @@ class AadUserRemoveCommand extends GraphCommand { await this.deleteUser(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove user '${args.options.id || args.options.userName}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove user '${args.options.id || args.options.userName}'?` }); - if (result.continue) { + if (result) { await this.deleteUser(args); } } diff --git a/src/m365/app/commands/permission/permission-add.spec.ts b/src/m365/app/commands/permission/permission-add.spec.ts index f3ac844914a..0d94fe6414d 100644 --- a/src/m365/app/commands/permission/permission-add.spec.ts +++ b/src/m365/app/commands/permission/permission-add.spec.ts @@ -46,6 +46,13 @@ describe(commands.PERMISSION_ADD, () => { })); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/booking/commands/business/business-get.spec.ts b/src/m365/booking/commands/business/business-get.spec.ts index b75f983a062..1cb13f05006 100644 --- a/src/m365/booking/commands/business/business-get.spec.ts +++ b/src/m365/booking/commands/business/business-get.spec.ts @@ -38,6 +38,13 @@ describe(commands.BUSINESS_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/commands/setup.spec.ts b/src/m365/commands/setup.spec.ts index 52e7109807e..0a9b1cd4893 100644 --- a/src/m365/commands/setup.spec.ts +++ b/src/m365/commands/setup.spec.ts @@ -11,6 +11,7 @@ import { sinonUtil } from '../../utils/sinonUtil.js'; import commands from './commands.js'; import command, { SettingNames } from './setup.js'; import { interactivePreset, powerShellPreset, scriptingPreset } from './setupPresets.js'; +import { ConfirmationConfig, SelectionConfig } from '../../utils/prompt.js'; describe(commands.SETUP, () => { let log: any[]; @@ -45,6 +46,8 @@ describe(commands.SETUP, () => { afterEach(() => { sinonUtil.restore([ (command as any).configureSettings, + Cli.promptForConfirmation, + Cli.promptForSelection, Cli.getInstance().config.set, pid.isPowerShell ]); @@ -67,11 +70,25 @@ describe(commands.SETUP, () => { }); it('sets correct settings for interactive, beginner', async () => { - (command as any).answers = { - usageMode: 'Interactively', - experience: 'Beginner', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Interactively'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return true; + default: //summary + return true; + } + }); + const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -85,11 +102,24 @@ describe(commands.SETUP, () => { }); it('sets correct settings for interactive, proficient', async () => { - (command as any).answers = { - usageMode: 'Interactively', - experience: 'Proficient', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Interactively'; + case 'How experienced are you in using the CLI?': + return 'Proficient'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return true; + default: //summary + return true; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -103,12 +133,24 @@ describe(commands.SETUP, () => { }); it('sets correct settings for scripting, non-PowerShell, beginner', async () => { - (command as any).answers = { - usageMode: 'Scripting', - usedInPowerShell: false, - experience: 'Beginner', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Scripting'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return false; + default: //summary + return true; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -122,12 +164,24 @@ describe(commands.SETUP, () => { }); it('sets correct settings for scripting, PowerShell, beginner', async () => { - (command as any).answers = { - usageMode: 'Scripting', - usedInPowerShell: true, - experience: 'Beginner', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Scripting'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return true; + default: //summary + return true; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -142,12 +196,24 @@ describe(commands.SETUP, () => { }); it('sets correct settings for scripting, non-PowerShell, proficient', async () => { - (command as any).answers = { - usageMode: 'Scripting', - usedInPowerShell: false, - experience: 'Proficient', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Scripting'; + case 'How experienced are you in using the CLI?': + return 'Proficient'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return false; + default: //summary + return true; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -161,12 +227,24 @@ describe(commands.SETUP, () => { }); it('sets correct settings for scripting, PowerShell, proficient', async () => { - (command as any).answers = { - usageMode: 'Scripting', - usedInPowerShell: true, - experience: 'Proficient', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Scripting'; + case 'How experienced are you in using the CLI?': + return 'Proficient'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return true; + default: //summary + return true; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); const expected: SettingNames = {}; @@ -181,12 +259,24 @@ describe(commands.SETUP, () => { }); it(`doesn't apply settings when not confirmed`, async () => { - (command as any).answers = { - usageMode: 'Scripting', - usedInPowerShell: false, - experience: 'Beginner', - summary: false - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Scripting'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return false; + default: //summary + return false; + } + }); const configureSettingsStub = sinon.stub(command as any, 'configureSettings').callsFake(() => { }); await command.action(logger, { options: {} }); @@ -247,11 +337,24 @@ describe(commands.SETUP, () => { }); it('outputs settings to configure to console in debug mode', async () => { - (command as any).answers = { - usageMode: 'Interactively', - experience: 'Beginner', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Interactively'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return false; + default: //summary + return true; + } + }); sinon.stub(Cli.getInstance().config, 'set').callsFake(() => { }); const expected: SettingNames = {}; @@ -265,11 +368,24 @@ describe(commands.SETUP, () => { }); it('logs configured settings when used interactively', async () => { - (command as any).answers = { - usageMode: 'Interactively', - experience: 'Beginner', - summary: true - }; + sinon.stub(Cli, 'promptForSelection').callsFake(async (config: SelectionConfig): Promise => { + switch (config.message) { + case 'How do you plan to use the CLI?': + return 'Interactively'; + case 'How experienced are you in using the CLI?': + return 'Beginner'; + default: + return ''; + } + }); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig): Promise => { + switch (config.message) { + case 'Are you going to use the CLI in PowerShell?': + return false; + default: //summary + return true; + } + }); sinon.stub(Cli.getInstance().config, 'set').callsFake(() => { }); const expected: SettingNames = {}; diff --git a/src/m365/commands/setup.ts b/src/m365/commands/setup.ts index 95705c895b8..8ec28d87ae7 100644 --- a/src/m365/commands/setup.ts +++ b/src/m365/commands/setup.ts @@ -9,7 +9,7 @@ import { pid } from '../../utils/pid.js'; import AnonymousCommand from '../base/AnonymousCommand.js'; import commands from './commands.js'; import { interactivePreset, powerShellPreset, scriptingPreset } from './setupPresets.js'; -import { prompt } from '../../utils/prompt.js'; +import { ConfirmationConfig, SelectionConfig } from '../../utils/prompt.js'; interface Preferences { experience?: string; @@ -32,9 +32,6 @@ export type SettingNames = { }; class SetupCommand extends AnonymousCommand { - // used for injecting answers from tests - private answers: Preferences = {}; - public get name(): string { return commands.SETUP; } @@ -107,43 +104,45 @@ class SetupCommand extends AnonymousCommand { await logger.logToStderr(`Please, answer the following questions and we'll define a set of settings to best match how you intend to use the CLI.`); await logger.logToStderr(''); - const preferences: Preferences = await prompt.forInput([ - { - type: 'list', - name: 'usageMode', - message: 'How do you plan to use the CLI?', - choices: [ - 'Interactively', - 'Scripting' - ] - }, - { - type: 'confirm', - name: 'usedInPowerShell', + const preferences: Preferences = {}; + + const usageModeConfig: SelectionConfig = { + message: 'How do you plan to use the CLI?', + choices: [ + { name: 'Interactively', value: 'Interactively' }, + { name: 'Scripting', value: 'Scripting' } + ] + }; + preferences.usageMode = await Cli.promptForSelection(usageModeConfig); + + if (preferences.usageMode === 'Scripting') { + const usedInPowerShellConfig: ConfirmationConfig = { message: 'Are you going to use the CLI in PowerShell?', - when: (answers: Preferences) => answers.usageMode === 'Scripting', default: pid.isPowerShell() - }, - { - type: 'list', - name: 'experience', - message: 'How experienced are you in using the CLI?', - choices: [ - 'Beginner', - 'Proficient' - ] - }, - { - type: 'confirm', - name: 'summary', - // invoked by inquirer - /* c8 ignore next 4 */ - message: (answers: Preferences) => { - settings = this.getSettings(answers); - return this.getSummaryMessage(settings); - } + }; + preferences.usedInPowerShell = await Cli.promptForConfirmation(usedInPowerShellConfig); + } + + const experienceConfig: SelectionConfig = { + message: 'How experienced are you in using the CLI?', + choices: [ + { name: 'Beginner', value: 'Beginner' }, + { name: 'Proficient', value: 'Proficient' } + ] + }; + preferences.experience = await Cli.promptForSelection(experienceConfig); + + const summaryConfig: ConfirmationConfig = { + // invoked by inquirer + /* c8 ignore next 6 */ + message: async (): Promise => { + settings = this.getSettings(preferences); + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return this.getSummaryMessage(settings); } - ], this.answers); + }; + preferences.summary = await Cli.promptForConfirmation(summaryConfig); if (preferences.summary) { // used only for testing. Normally, we'd get the settings from the answers diff --git a/src/m365/context/commands/context-remove.spec.ts b/src/m365/context/commands/context-remove.spec.ts index 5c41ab3339c..9ee745aed4d 100644 --- a/src/m365/context/commands/context-remove.spec.ts +++ b/src/m365/context/commands/context-remove.spec.ts @@ -12,7 +12,7 @@ import command from './context-remove.js'; describe(commands.REMOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(telemetry, 'trackEvent').callsFake(() => { }); @@ -31,11 +31,12 @@ describe(commands.REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { @@ -44,7 +45,7 @@ describe(commands.REMOVE, () => { fs.readFileSync, fs.writeFileSync, fs.unlinkSync, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -60,17 +61,12 @@ describe(commands.REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the context from the .m365rc.json file when confirm option not passed', async () => { + it('prompts before removing the context from the .m365rc.json file when force option not passed', async () => { await command.action(logger, { options: { debug: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -90,10 +86,8 @@ describe(commands.REMOVE, () => { let fileContents: string | undefined; let filePath: string | undefined; - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(fs, 'existsSync').callsFake(_ => true); sinon.stub(fs, 'readFileSync').callsFake(_ => JSON.stringify({ diff --git a/src/m365/context/commands/context-remove.ts b/src/m365/context/commands/context-remove.ts index 7c1480118e4..208b10d2527 100644 --- a/src/m365/context/commands/context-remove.ts +++ b/src/m365/context/commands/context-remove.ts @@ -52,14 +52,9 @@ class ContextRemoveCommand extends AnonymousCommand { await this.removeContext(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the context?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the context?` }); - if (result.continue) { + if (result) { await this.removeContext(); } } diff --git a/src/m365/context/commands/option/option-remove.spec.ts b/src/m365/context/commands/option/option-remove.spec.ts index ce2e05c2196..dbb5ecf667f 100644 --- a/src/m365/context/commands/option/option-remove.spec.ts +++ b/src/m365/context/commands/option/option-remove.spec.ts @@ -12,7 +12,7 @@ import command from './option-remove.js'; describe(commands.OPTION_REMOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(telemetry, 'trackEvent').callsFake(() => { }); @@ -31,11 +31,12 @@ describe(commands.OPTION_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { @@ -43,7 +44,7 @@ describe(commands.OPTION_REMOVE, () => { fs.existsSync, fs.readFileSync, fs.writeFileSync, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -59,17 +60,12 @@ describe(commands.OPTION_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the context option from the .m365rc.json file when confirm option not passed', async () => { + it('prompts before removing the context option from the .m365rc.json file when force option not passed', async () => { await command.action(logger, { options: { debug: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -100,10 +96,8 @@ describe(commands.OPTION_REMOVE, () => { }); it(`removes a context info option from the existing .m365rc.json file`, async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(fs, 'existsSync').callsFake(_ => true); sinon.stub(fs, 'readFileSync').callsFake(_ => JSON.stringify({ diff --git a/src/m365/context/commands/option/option-remove.ts b/src/m365/context/commands/option/option-remove.ts index 59d95c71673..d612cf1c434 100644 --- a/src/m365/context/commands/option/option-remove.ts +++ b/src/m365/context/commands/option/option-remove.ts @@ -60,14 +60,9 @@ class ContextOptionRemoveCommand extends ContextCommand { await this.removeContextOption(args.options.name, logger); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the context option ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the context option ${args.options.name}?` }); - if (result.continue) { + if (result) { await this.removeContextOption(args.options.name, logger); } } diff --git a/src/m365/flow/commands/flow-remove.spec.ts b/src/m365/flow/commands/flow-remove.spec.ts index 15ddbaf49b7..2dd02404c13 100644 --- a/src/m365/flow/commands/flow-remove.spec.ts +++ b/src/m365/flow/commands/flow-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,17 +43,18 @@ describe(commands.REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -90,26 +91,21 @@ describe(commands.REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified Microsoft Flow owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified Microsoft Flow owned by the currently signed-in user when force option not passed', async () => { await command.action(logger, { options: { environmentName: 'Default-eff8592e-e14a-4ae8-8771-d96d5c549e1c', name: '0f64d9dd-01bb-4c1b-95b3-cb4a1a08ac72' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified Microsoft Flow owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified Microsoft Flow owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -129,8 +125,8 @@ describe(commands.REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -142,7 +138,7 @@ describe(commands.REMOVE, () => { assert(loggerLogToStderrSpy.called); }); - it('prompts before removing the specified Microsoft Flow owned by another user when confirm option not passed', async () => { + it('prompts before removing the specified Microsoft Flow owned by another user when force option not passed', async () => { await command.action(logger, { options: { environmentName: 'Default-eff8592e-e14a-4ae8-8771-d96d5c549e1c', @@ -150,19 +146,14 @@ describe(commands.REMOVE, () => { asAdmin: true } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified Microsoft Flow owned by another user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified Microsoft Flow owned by another user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -183,8 +174,8 @@ describe(commands.REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -264,8 +255,8 @@ describe(commands.REMOVE, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -279,8 +270,8 @@ describe(commands.REMOVE, () => { it('correctly handles no Microsoft Flow found when prompt confirmed', async () => { sinon.stub(request, 'delete').resolves({ statusCode: 204 }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: diff --git a/src/m365/flow/commands/flow-remove.ts b/src/m365/flow/commands/flow-remove.ts index 58912b88616..568ac261953 100644 --- a/src/m365/flow/commands/flow-remove.ts +++ b/src/m365/flow/commands/flow-remove.ts @@ -105,14 +105,9 @@ class FlowRemoveCommand extends AzmgmtCommand { await removeFlow(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the Microsoft Flow ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the Microsoft Flow ${args.options.name}?` }); - if (result.continue) { + if (result) { await removeFlow(); } } diff --git a/src/m365/flow/commands/owner/owner-remove.spec.ts b/src/m365/flow/commands/owner/owner-remove.spec.ts index ae8c222e348..f2b03fd7a8b 100644 --- a/src/m365/flow/commands/owner/owner-remove.spec.ts +++ b/src/m365/flow/commands/owner/owner-remove.spec.ts @@ -31,7 +31,7 @@ describe(commands.OWNER_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -55,18 +55,19 @@ describe(commands.OWNER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ aadGroup.getGroupIdByDisplayName, aadUser.getUserIdByUpn, - Cli.prompt, + Cli.promptForConfirmation, request.post ]); }); @@ -112,8 +113,8 @@ describe(commands.OWNER_REMOVE, () => { }); it('deletes owner from flow by groupId as admin when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const postStub = sinon.stub(request, 'post').callsFake(async opts => { if (opts.url === requestUrlAdmin) { return; @@ -153,21 +154,16 @@ describe(commands.OWNER_REMOVE, () => { new CommandError(error.error.message)); }); - it('prompts before removing the specified owner from a flow when confirm option not passed', async () => { + it('prompts before removing the specified owner from a flow when force option not passed', async () => { await command.action(logger, { options: { environmentName: environmentName, flowName: flowName, useName: userName } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing the specified owner from a flow when option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { environmentName: environmentName, flowName: flowName, useName: userName } }); assert(postSpy.notCalled); diff --git a/src/m365/flow/commands/owner/owner-remove.ts b/src/m365/flow/commands/owner/owner-remove.ts index bfa747416e4..ce2abff373f 100644 --- a/src/m365/flow/commands/owner/owner-remove.ts +++ b/src/m365/flow/commands/owner/owner-remove.ts @@ -154,14 +154,9 @@ class FlowOwnerRemoveCommand extends AzmgmtCommand { await removeFlowOwner(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove owner '${args.options.groupId || args.options.groupName || args.options.userId || args.options.userName}' from the specified flow?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove owner '${args.options.groupId || args.options.groupName || args.options.userId || args.options.userName}' from the specified flow?` }); + + if (result) { await removeFlowOwner(); } } diff --git a/src/m365/flow/commands/run/run-cancel.spec.ts b/src/m365/flow/commands/run/run-cancel.spec.ts index 0b2997c838f..36ced61888d 100644 --- a/src/m365/flow/commands/run/run-cancel.spec.ts +++ b/src/m365/flow/commands/run/run-cancel.spec.ts @@ -18,7 +18,7 @@ describe(commands.RUN_CANCEL, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,17 +43,18 @@ describe(commands.RUN_CANCEL, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -92,7 +93,7 @@ describe(commands.RUN_CANCEL, () => { assert.strictEqual(actual, true); }); - it('prompts before cancelling the specified Microsoft FlowName when confirm option not passed', async () => { + it('prompts before cancelling the specified Microsoft FlowName when force option not passed', async () => { await command.action(logger, { options: { environmentName: 'Default-eff8592e-e14a-4ae8-8771-d96d5c549e1c', @@ -101,19 +102,14 @@ describe(commands.RUN_CANCEL, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts cancelling the specified Microsoft FlowName when confirm option not passed and prompt not confirmed', async () => { + it('aborts cancelling the specified Microsoft FlowName when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { environmentName: 'Default-eff8592e-e14a-4ae8-8771-d96d5c549e1c', @@ -154,8 +150,8 @@ describe(commands.RUN_CANCEL, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -195,8 +191,8 @@ describe(commands.RUN_CANCEL, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -216,8 +212,8 @@ describe(commands.RUN_CANCEL, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -256,8 +252,8 @@ describe(commands.RUN_CANCEL, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: diff --git a/src/m365/flow/commands/run/run-cancel.ts b/src/m365/flow/commands/run/run-cancel.ts index 563a67f1322..13dca75a0d1 100644 --- a/src/m365/flow/commands/run/run-cancel.ts +++ b/src/m365/flow/commands/run/run-cancel.ts @@ -97,14 +97,9 @@ class FlowRunCancelCommand extends AzmgmtCommand { await cancelFlow(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to cancel the flow run ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to cancel the flow run ${args.options.name}?` }); - if (result.continue) { + if (result) { await cancelFlow(); } } diff --git a/src/m365/flow/commands/run/run-resubmit.spec.ts b/src/m365/flow/commands/run/run-resubmit.spec.ts index c3045cdeccb..5aa97769489 100644 --- a/src/m365/flow/commands/run/run-resubmit.spec.ts +++ b/src/m365/flow/commands/run/run-resubmit.spec.ts @@ -18,7 +18,7 @@ describe(commands.RUN_RESUBMIT, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,18 +43,19 @@ describe(commands.RUN_RESUBMIT, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, request.get, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -93,7 +94,7 @@ describe(commands.RUN_RESUBMIT, () => { assert.strictEqual(actual, true); }); - it('prompts before resubmitting the specified Microsoft Flow when confirm option not passed', async () => { + it('prompts before resubmitting the specified Microsoft Flow when force option not passed', async () => { await command.action(logger, { options: { environmentName: 'Default-eff8592e-e14a-4ae8-8771-d96d5c549e1c', @@ -102,20 +103,15 @@ describe(commands.RUN_RESUBMIT, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts resubmitting the specified Microsoft Flow when confirm option not passed and prompt not confirmed', async () => { + it('aborts resubmitting the specified Microsoft Flow when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); const getSpy = sinon.spy(request, 'get'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -136,8 +132,8 @@ describe(commands.RUN_RESUBMIT, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -157,8 +153,8 @@ describe(commands.RUN_RESUBMIT, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -203,8 +199,8 @@ describe(commands.RUN_RESUBMIT, () => { } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -249,8 +245,8 @@ describe(commands.RUN_RESUBMIT, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: diff --git a/src/m365/flow/commands/run/run-resubmit.ts b/src/m365/flow/commands/run/run-resubmit.ts index 4f56e51212e..5ff7b81f10c 100644 --- a/src/m365/flow/commands/run/run-resubmit.ts +++ b/src/m365/flow/commands/run/run-resubmit.ts @@ -105,14 +105,9 @@ class FlowRunResubmitCommand extends AzmgmtCommand { await resubmitFlow(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to resubmit the flow with run ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to resubmit the flow with run ${args.options.name}?` }); - if (result.continue) { + if (result) { await resubmitFlow(); } } diff --git a/src/m365/graph/commands/schemaextension/schemaextension-remove.spec.ts b/src/m365/graph/commands/schemaextension/schemaextension-remove.spec.ts index 0bcb250d27a..0d2bffd1086 100644 --- a/src/m365/graph/commands/schemaextension/schemaextension-remove.spec.ts +++ b/src/m365/graph/commands/schemaextension/schemaextension-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.SCHEMAEXTENSION_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -42,17 +42,18 @@ describe(commands.SCHEMAEXTENSION_REMOVE, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -97,19 +98,14 @@ describe(commands.SCHEMAEXTENSION_REMOVE, () => { it('prompts before removing schema extension when confirmation argument not passed', async () => { await command.action(logger, { options: { id: 'exttyee4dv5_MySchemaExtension' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing schema extension when prompt not confirmed', async () => { sinon.stub(request, 'delete').rejects('Invalid request'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'exttyee4dv5_MySchemaExtension' } }); }); @@ -123,8 +119,8 @@ describe(commands.SCHEMAEXTENSION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'exttyee4dv5_MySchemaExtension' } }); assert(loggerLogSpy.notCalled); diff --git a/src/m365/graph/commands/schemaextension/schemaextension-remove.ts b/src/m365/graph/commands/schemaextension/schemaextension-remove.ts index 2a1166c7d29..ec171d304cd 100644 --- a/src/m365/graph/commands/schemaextension/schemaextension-remove.ts +++ b/src/m365/graph/commands/schemaextension/schemaextension-remove.ts @@ -76,14 +76,9 @@ class GraphSchemaExtensionRemoveCommand extends GraphCommand { await removeSchemaExtension(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the schema extension with ID ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the schema extension with ID ${args.options.id}?` }); - if (result.continue) { + if (result) { await removeSchemaExtension(); } } diff --git a/src/m365/onenote/commands/page/page-list.spec.ts b/src/m365/onenote/commands/page/page-list.spec.ts index 990f2dd8f65..5a0023a4c15 100644 --- a/src/m365/onenote/commands/page/page-list.spec.ts +++ b/src/m365/onenote/commands/page/page-list.spec.ts @@ -83,6 +83,13 @@ describe(commands.PAGE_LIST, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/pa/commands/app/app-consent-set.spec.ts b/src/m365/pa/commands/app/app-consent-set.spec.ts index 466a924f6d3..6e8693600b6 100644 --- a/src/m365/pa/commands/app/app-consent-set.spec.ts +++ b/src/m365/pa/commands/app/app-consent-set.spec.ts @@ -22,7 +22,7 @@ describe(commands.APP_CONSENT_SET, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -46,17 +46,18 @@ describe(commands.APP_CONSENT_SET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -95,7 +96,7 @@ describe(commands.APP_CONSENT_SET, () => { assert.strictEqual(actual, true); }); - it('prompts before bypassing consent for the specified Microsoft Power App when confirm option not passed', async () => { + it('prompts before bypassing consent for the specified Microsoft Power App when force option not passed', async () => { await command.action(logger, { options: { environmentName: environmentName, @@ -103,19 +104,14 @@ describe(commands.APP_CONSENT_SET, () => { bypass: true } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts bypassing the consent for the specified Microsoft Power App when confirm option not passed and prompt not confirmed', async () => { + it('aborts bypassing the consent for the specified Microsoft Power App when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -136,8 +132,8 @@ describe(commands.APP_CONSENT_SET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.doesNotReject(command.action(logger, { options: { diff --git a/src/m365/pa/commands/app/app-consent-set.ts b/src/m365/pa/commands/app/app-consent-set.ts index 51c45a1b269..be5929dc777 100644 --- a/src/m365/pa/commands/app/app-consent-set.ts +++ b/src/m365/pa/commands/app/app-consent-set.ts @@ -77,14 +77,9 @@ class PaAppConsentSetCommand extends PowerAppsCommand { await this.consentPaApp(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you bypass the consent for the Microsoft Power App ${args.options.name} to ${args.options.bypass}?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you bypass the consent for the Microsoft Power App ${args.options.name} to ${args.options.bypass}?` }); + + if (result) { await this.consentPaApp(args); } } diff --git a/src/m365/pa/commands/app/app-permission-remove.spec.ts b/src/m365/pa/commands/app/app-permission-remove.spec.ts index f11be59e756..138b47a61c5 100644 --- a/src/m365/pa/commands/app/app-permission-remove.spec.ts +++ b/src/m365/pa/commands/app/app-permission-remove.spec.ts @@ -21,7 +21,7 @@ describe(commands.APP_PERMISSION_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validEnvironmentName = 'Default-6a2903af-9c03-4c02-a50b-e7419599925b'; const validAppName = '784670e6-199a-4993-ae13-4b6747a0cd5d'; @@ -85,11 +85,13 @@ describe(commands.APP_PERMISSION_REMOVE, () => { } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + promptIssued = false; + sinon.stub(accessToken, 'getTenantIdFromAccessToken').returns(tenantId); sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((_, defaultValue) => defaultValue); }); @@ -98,7 +100,7 @@ describe(commands.APP_PERMISSION_REMOVE, () => { sinonUtil.restore([ request.post, cli.getSettingWithDefaultValue, - Cli.prompt, + Cli.promptForConfirmation, aadUser.getUserIdByUpn, aadGroup.getGroupByDisplayName, accessToken.getTenantIdFromAccessToken @@ -183,11 +185,6 @@ describe(commands.APP_PERMISSION_REMOVE, () => { userId: validUserId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -218,8 +215,8 @@ describe(commands.APP_PERMISSION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const requestBody = { delete: [{ id: `tenant-${tenantId}` }] diff --git a/src/m365/pa/commands/app/app-permission-remove.ts b/src/m365/pa/commands/app/app-permission-remove.ts index 4ccd8f96761..6e17019fb00 100644 --- a/src/m365/pa/commands/app/app-permission-remove.ts +++ b/src/m365/pa/commands/app/app-permission-remove.ts @@ -138,14 +138,9 @@ class PaAppPermissionRemoveCommand extends PowerAppsCommand { await this.removeAppPermission(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the permissions of '${args.options.userId || args.options.userName || args.options.groupId || args.options.groupName || (args.options.tenant && 'everyone')}' from the Power App '${args.options.appName}'?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the permissions of '${args.options.userId || args.options.userName || args.options.groupId || args.options.groupName || (args.options.tenant && 'everyone')}' from the Power App '${args.options.appName}'?` }); + + if (result) { await this.removeAppPermission(logger, args.options); } } diff --git a/src/m365/pa/commands/app/app-remove.spec.ts b/src/m365/pa/commands/app/app-remove.spec.ts index 990f4c3a1d9..6b82a1c9acd 100644 --- a/src/m365/pa/commands/app/app-remove.spec.ts +++ b/src/m365/pa/commands/app/app-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_REMOVE, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,17 +43,18 @@ describe(commands.APP_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -88,25 +89,20 @@ describe(commands.APP_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified Microsoft Power App when confirm option not passed', async () => { + it('prompts before removing the specified Microsoft Power App when force option not passed', async () => { await command.action(logger, { options: { name: 'e0c89645-7f00-4877-a290-cbaf6e060da1' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified Microsoft Power App when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified Microsoft Power App when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -125,8 +121,8 @@ describe(commands.APP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -146,8 +142,8 @@ describe(commands.APP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -199,8 +195,8 @@ describe(commands.APP_REMOVE, () => { it('correctly handles no Microsoft Power App found when prompt confirmed', async () => { sinon.stub(request, 'delete').rejects({ response: { status: 403 } }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: @@ -225,8 +221,8 @@ describe(commands.APP_REMOVE, () => { it('correctly handles Microsoft Power App found when prompt confirmed', async () => { sinon.stub(request, 'delete').resolves({ statusCode: 200 }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: @@ -273,8 +269,8 @@ describe(commands.APP_REMOVE, () => { it('correctly handles random api error', async () => { sinon.stub(request, 'delete').rejects(new Error("Something went wrong")); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: diff --git a/src/m365/pa/commands/app/app-remove.ts b/src/m365/pa/commands/app/app-remove.ts index e29db0c8a42..520d8006995 100644 --- a/src/m365/pa/commands/app/app-remove.ts +++ b/src/m365/pa/commands/app/app-remove.ts @@ -97,14 +97,9 @@ class PaAppRemoveCommand extends PowerAppsCommand { await removePaApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the Microsoft Power App ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the Microsoft Power App ${args.options.name}?` }); - if (result.continue) { + if (result) { await removePaApp(); } } diff --git a/src/m365/planner/commands/bucket/bucket-get.spec.ts b/src/m365/planner/commands/bucket/bucket-get.spec.ts index 5723f9b5a3e..34099283b0a 100644 --- a/src/m365/planner/commands/bucket/bucket-get.spec.ts +++ b/src/m365/planner/commands/bucket/bucket-get.spec.ts @@ -86,7 +86,6 @@ describe(commands.BUCKET_GET, () => { ] }; - let cli: Cli; const planResponse = { value: [{ id: validPlanId, @@ -100,7 +99,6 @@ describe(commands.BUCKET_GET, () => { let commandInfo: CommandInfo; before(() => { - cli = Cli.getInstance(); sinon.stub(auth, 'restoreAuth').resolves(); sinon.stub(telemetry, 'trackEvent').returns(); sinon.stub(pid, 'getProcessName').returns(''); @@ -111,6 +109,13 @@ describe(commands.BUCKET_GET, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -128,14 +133,12 @@ describe(commands.BUCKET_GET, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); (command as any).items = []; - sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.get, request.patch, - cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); }); diff --git a/src/m365/planner/commands/bucket/bucket-remove.spec.ts b/src/m365/planner/commands/bucket/bucket-remove.spec.ts index 1eb2ddde4e9..296f94e8934 100644 --- a/src/m365/planner/commands/bucket/bucket-remove.spec.ts +++ b/src/m365/planner/commands/bucket/bucket-remove.spec.ts @@ -96,7 +96,7 @@ describe(commands.BUCKET_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -109,6 +109,13 @@ describe(commands.BUCKET_REMOVE, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -124,18 +131,19 @@ describe(commands.BUCKET_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -239,23 +247,18 @@ describe(commands.BUCKET_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified bucket when confirm option not passed with id', async () => { + it('prompts before removing the specified bucket when force option not passed with id', async () => { await command.action(logger, { options: { id: validBucketId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified bucket when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified bucket when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -360,8 +363,8 @@ describe(commands.BUCKET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'handleMultipleResultsFound').resolves(singleBucketByNameResponse.value[0]); @@ -449,8 +452,8 @@ describe(commands.BUCKET_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -480,8 +483,8 @@ describe(commands.BUCKET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.doesNotReject(command.action(logger, { options: { diff --git a/src/m365/planner/commands/bucket/bucket-remove.ts b/src/m365/planner/commands/bucket/bucket-remove.ts index b7c442f6322..0a93cc0c870 100644 --- a/src/m365/planner/commands/bucket/bucket-remove.ts +++ b/src/m365/planner/commands/bucket/bucket-remove.ts @@ -162,14 +162,9 @@ class PlannerBucketRemoveCommand extends GraphCommand { await removeBucket(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the bucket ${args.options.id || args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the bucket ${args.options.id || args.options.name}?` }); - if (result.continue) { + if (result) { await removeBucket(); } } diff --git a/src/m365/planner/commands/bucket/bucket-set.spec.ts b/src/m365/planner/commands/bucket/bucket-set.spec.ts index 814564f38ec..8ae82544a48 100644 --- a/src/m365/planner/commands/bucket/bucket-set.spec.ts +++ b/src/m365/planner/commands/bucket/bucket-set.spec.ts @@ -109,6 +109,13 @@ describe(commands.BUCKET_SET, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/planner/commands/plan/plan-remove.spec.ts b/src/m365/planner/commands/plan/plan-remove.spec.ts index c20496386b8..2cd691b5bdb 100644 --- a/src/m365/planner/commands/plan/plan-remove.spec.ts +++ b/src/m365/planner/commands/plan/plan-remove.spec.ts @@ -49,7 +49,7 @@ describe(commands.PLAN_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -78,18 +78,19 @@ describe(commands.PLAN_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -166,23 +167,18 @@ describe(commands.PLAN_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified plan when confirm option not passed with id', async () => { + it('prompts before removing the specified plan when force option not passed with id', async () => { await command.action(logger, { options: { id: validPlanId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified plan when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified plan when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -234,10 +230,8 @@ describe(commands.PLAN_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -262,8 +256,8 @@ describe(commands.PLAN_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/planner/commands/plan/plan-remove.ts b/src/m365/planner/commands/plan/plan-remove.ts index ec0f2c97dd3..4a45a785e20 100644 --- a/src/m365/planner/commands/plan/plan-remove.ts +++ b/src/m365/planner/commands/plan/plan-remove.ts @@ -130,13 +130,9 @@ class PlannerPlanRemoveCommand extends GraphCommand { await removePlan(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the plan ${args.options.id || args.options.title}?` - }); - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the plan ${args.options.id || args.options.title}?` }); + + if (result) { await removePlan(); } } diff --git a/src/m365/planner/commands/roster/roster-member-remove.spec.ts b/src/m365/planner/commands/roster/roster-member-remove.spec.ts index ab95e21be10..027f9edd30e 100644 --- a/src/m365/planner/commands/roster/roster-member-remove.spec.ts +++ b/src/m365/planner/commands/roster/roster-member-remove.spec.ts @@ -13,6 +13,7 @@ import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; import command from './roster-member-remove.js'; +import { ConfirmationConfig } from '../../../../utils/prompt.js'; describe(commands.ROSTER_MEMBER_REMOVE, () => { let commandInfo: CommandInfo; @@ -43,7 +44,7 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -67,18 +68,19 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, request.get, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -125,32 +127,27 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified roster member when confirm option not passed', async () => { + it('prompts before removing the specified roster member when force option not passed', async () => { await command.action(logger, { options: { rosterId: validRosterId, userId: validUserId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the last roster member when confirm option not passed', async () => { - let secondPromptOptions: any; - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - if (options.message === `Are you sure you want to remove member '${validUserId}'?`) { - return { continue: true }; + it('prompts before removing the last roster member when force option not passed', async () => { + let secondPromptConfirm: boolean = false; + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').callsFake(async (config: ConfirmationConfig) => { + if (config.message === `Are you sure you want to remove member '${validUserId}'?`) { + return true; } else { - secondPromptOptions = options; - return { continue: false }; + secondPromptConfirm = true; + return false; } }); @@ -171,14 +168,14 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { let promptIssued = false; - if (secondPromptOptions && secondPromptOptions.type === 'confirm') { + if (secondPromptConfirm) { promptIssued = true; } assert(promptIssued); }); - it('aborts removing the specified roster member when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified roster member when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { @@ -212,8 +209,8 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -247,8 +244,8 @@ describe(commands.ROSTER_MEMBER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/planner/commands/roster/roster-member-remove.ts b/src/m365/planner/commands/roster/roster-member-remove.ts index 295081eaccd..e955a16edd0 100644 --- a/src/m365/planner/commands/roster/roster-member-remove.ts +++ b/src/m365/planner/commands/roster/roster-member-remove.ts @@ -100,14 +100,9 @@ class PlannerRosterMemberRemoveCommand extends GraphCommand { await this.removeRosterMember(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove member '${args.options.userId || args.options.userName}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove member '${args.options.userId || args.options.userName}'?` }); - if (result.continue) { + if (result) { await this.removeRosterMember(args); } } @@ -147,14 +142,9 @@ class PlannerRosterMemberRemoveCommand extends GraphCommand { if (!args.options.force) { const rosterMembers = await odata.getAllItems(`${this.resource}/beta/planner/rosters/${args.options.rosterId}/members?$select=Id`); if (rosterMembers.length === 1) { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `You are about to remove the last member of this Roster. When this happens, the Roster and all its contents will be deleted within 30 days. Are you sure you want to proceed?` - }); - - return result.continue; + const result = await Cli.promptForConfirmation({ message: `You are about to remove the last member of this Roster. When this happens, the Roster and all its contents will be deleted within 30 days. Are you sure you want to proceed?` }); + + return result; } } diff --git a/src/m365/planner/commands/roster/roster-remove.spec.ts b/src/m365/planner/commands/roster/roster-remove.spec.ts index 1ded3d895fa..7b2911baf0a 100644 --- a/src/m365/planner/commands/roster/roster-remove.spec.ts +++ b/src/m365/planner/commands/roster/roster-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.PLAN_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -44,17 +44,18 @@ describe(commands.PLAN_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -72,23 +73,18 @@ describe(commands.PLAN_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the specified Roster when confirm option not passed', async () => { + it('prompts before removing the specified Roster when force option not passed', async () => { await command.action(logger, { options: { id: validRosterId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified Roster when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified Roster when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -125,8 +121,8 @@ describe(commands.PLAN_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/planner/commands/roster/roster-remove.ts b/src/m365/planner/commands/roster/roster-remove.ts index 3d8f7de1a33..2195c0b83b4 100644 --- a/src/m365/planner/commands/roster/roster-remove.ts +++ b/src/m365/planner/commands/roster/roster-remove.ts @@ -59,13 +59,9 @@ class PlannerRosterRemoveCommand extends GraphCommand { await this.removeRoster(args, logger); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove roster ${args.options.id}?` - }); - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove roster ${args.options.id}?` }); + + if (result) { await this.removeRoster(args, logger); } } diff --git a/src/m365/planner/commands/task/task-checklistitem-remove.spec.ts b/src/m365/planner/commands/task/task-checklistitem-remove.spec.ts index 24f3a34521a..357d3d72cbd 100644 --- a/src/m365/planner/commands/task/task-checklistitem-remove.spec.ts +++ b/src/m365/planner/commands/task/task-checklistitem-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.TASK_CHECKLISTITEM_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validTaskId = '2Vf8JHgsBUiIf-nuvBtv-ZgAAYw2'; const validId = '71175'; @@ -63,19 +63,19 @@ describe(commands.TASK_CHECKLISTITEM_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: true }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(true); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.patch, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -93,11 +93,11 @@ describe(commands.TASK_CHECKLISTITEM_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removal when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + it('prompts before removal when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); await command.action(logger, { @@ -107,12 +107,6 @@ describe(commands.TASK_CHECKLISTITEM_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); }); diff --git a/src/m365/planner/commands/task/task-checklistitem-remove.ts b/src/m365/planner/commands/task/task-checklistitem-remove.ts index b4892996dbc..c4d509c0411 100644 --- a/src/m365/planner/commands/task/task-checklistitem-remove.ts +++ b/src/m365/planner/commands/task/task-checklistitem-remove.ts @@ -59,14 +59,9 @@ class PlannerTaskChecklistItemRemoveCommand extends GraphCommand { await this.removeChecklistitem(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the checklist item with id ${args.options.id} from the planner task?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the checklist item with id ${args.options.id} from the planner task?` }); - if (result.continue) { + if (result) { await this.removeChecklistitem(args); } } diff --git a/src/m365/planner/commands/task/task-get.spec.ts b/src/m365/planner/commands/task/task-get.spec.ts index ab97e79c2cd..ae05878ef4b 100644 --- a/src/m365/planner/commands/task/task-get.spec.ts +++ b/src/m365/planner/commands/task/task-get.spec.ts @@ -141,6 +141,13 @@ describe(commands.TASK_GET, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/planner/commands/task/task-list.spec.ts b/src/m365/planner/commands/task/task-list.spec.ts index 6c8f5d74706..bc339fb7c99 100644 --- a/src/m365/planner/commands/task/task-list.spec.ts +++ b/src/m365/planner/commands/task/task-list.spec.ts @@ -283,6 +283,13 @@ describe(commands.TASK_LIST, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/planner/commands/task/task-reference-remove.spec.ts b/src/m365/planner/commands/task/task-reference-remove.spec.ts index 984e20bd108..c52b84fd8ec 100644 --- a/src/m365/planner/commands/task/task-reference-remove.spec.ts +++ b/src/m365/planner/commands/task/task-reference-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.TASK_REFERENCE_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validTaskId = '2Vf8JHgsBUiIf-nuvBtv-ZgAAYw2'; const validUrl = 'https://www.microsoft.com'; const validAlias = 'Test'; @@ -78,19 +78,19 @@ describe(commands.TASK_REFERENCE_REMOVE, () => { } }; - promptOptions = undefined; - - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: true }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(true); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.patch, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -138,11 +138,11 @@ describe(commands.TASK_REFERENCE_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removal when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + it('prompts before removal when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); await command.action(logger, { @@ -152,12 +152,6 @@ describe(commands.TASK_REFERENCE_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); }); diff --git a/src/m365/planner/commands/task/task-reference-remove.ts b/src/m365/planner/commands/task/task-reference-remove.ts index 427b03f727f..001e1433a40 100644 --- a/src/m365/planner/commands/task/task-reference-remove.ts +++ b/src/m365/planner/commands/task/task-reference-remove.ts @@ -83,14 +83,9 @@ class PlannerTaskReferenceRemoveCommand extends GraphCommand { await this.removeReference(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the reference from the Planner task?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the reference from the Planner task?` }); - if (result.continue) { + if (result) { await this.removeReference(logger, args); } } diff --git a/src/m365/planner/commands/task/task-remove.spec.ts b/src/m365/planner/commands/task/task-remove.spec.ts index 62562efed88..b51809dc67f 100644 --- a/src/m365/planner/commands/task/task-remove.spec.ts +++ b/src/m365/planner/commands/task/task-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.TASK_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validTaskId = '2Vf8JHgsBUiIf-nuvBtv-ZgAAYw2'; const validTaskTitle = 'Task name'; @@ -147,11 +147,12 @@ describe(commands.TASK_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -159,7 +160,7 @@ describe(commands.TASK_REMOVE, () => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); @@ -408,8 +409,8 @@ describe(commands.TASK_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'handleMultipleResultsFound').resolves(singleBucketByNameResponse.value[0]); @@ -491,8 +492,8 @@ describe(commands.TASK_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'handleMultipleResultsFound').resolves(singleTaskByTitleResponse.value[0]); @@ -507,23 +508,18 @@ describe(commands.TASK_REMOVE, () => { assert(removeRequestIssued); }); - it('prompts before removing the specified task when confirm option not passed with id', async () => { + it('prompts before removing the specified task when force option not passed with id', async () => { await command.action(logger, { options: { id: validTaskId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified task when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified task when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { @@ -585,8 +581,8 @@ describe(commands.TASK_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -626,8 +622,8 @@ describe(commands.TASK_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -664,10 +660,8 @@ describe(commands.TASK_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/planner/commands/task/task-remove.ts b/src/m365/planner/commands/task/task-remove.ts index 66d2bb606df..2c572b9522b 100644 --- a/src/m365/planner/commands/task/task-remove.ts +++ b/src/m365/planner/commands/task/task-remove.ts @@ -158,14 +158,9 @@ class PlannerTaskRemoveCommand extends GraphCommand { await removeTask(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the task ${args.options.id || args.options.title}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the task ${args.options.id || args.options.title}?` }); - if (result.continue) { + if (result) { await removeTask(); } } diff --git a/src/m365/planner/commands/task/task-set.spec.ts b/src/m365/planner/commands/task/task-set.spec.ts index 5bc19139cf8..76ac31b4430 100644 --- a/src/m365/planner/commands/task/task-set.spec.ts +++ b/src/m365/planner/commands/task/task-set.spec.ts @@ -150,6 +150,13 @@ describe(commands.TASK_SET, () => { expiresOn: new Date() }; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/pp/commands/aibuildermodel/aibuildermodel-get.spec.ts b/src/m365/pp/commands/aibuildermodel/aibuildermodel-get.spec.ts index bfb8a8c2fd2..2e32fcfe142 100644 --- a/src/m365/pp/commands/aibuildermodel/aibuildermodel-get.spec.ts +++ b/src/m365/pp/commands/aibuildermodel/aibuildermodel-get.spec.ts @@ -76,6 +76,13 @@ describe(commands.AIBUILDERMODEL_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.spec.ts b/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.spec.ts index ae7500566fb..bee0d0345db 100644 --- a/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.spec.ts +++ b/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.spec.ts @@ -64,7 +64,7 @@ describe(commands.AIBUILDERMODEL_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -90,18 +90,19 @@ describe(commands.AIBUILDERMODEL_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -139,7 +140,7 @@ describe(commands.AIBUILDERMODEL_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified AI builder model owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified AI builder model owned by the currently signed-in user when force option not passed', async () => { sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').callsFake(async () => envUrl); await command.action(logger, { @@ -148,21 +149,14 @@ describe(commands.AIBUILDERMODEL_REMOVE, () => { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified AI builder model owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified AI builder model owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { environmentName: validEnvironment, @@ -193,10 +187,8 @@ describe(commands.AIBUILDERMODEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.ts b/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.ts index 6df044c865e..47e8c5dfd35 100644 --- a/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.ts +++ b/src/m365/pp/commands/aibuildermodel/aibuildermodel-remove.ts @@ -98,14 +98,9 @@ class PpAiBuilderModelRemoveCommand extends PowerPlatformCommand { await this.deleteAiBuilderModel(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove AI builder model '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove AI builder model '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.deleteAiBuilderModel(args); } } diff --git a/src/m365/pp/commands/card/card-clone.spec.ts b/src/m365/pp/commands/card/card-clone.spec.ts index 4fc4364230c..4e955fca51c 100644 --- a/src/m365/pp/commands/card/card-clone.spec.ts +++ b/src/m365/pp/commands/card/card-clone.spec.ts @@ -60,7 +60,7 @@ describe(commands.CARD_CLONE, () => { request.get, request.post, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); diff --git a/src/m365/pp/commands/card/card-get.spec.ts b/src/m365/pp/commands/card/card-get.spec.ts index bdbe9a6b650..3eb356b1ffa 100644 --- a/src/m365/pp/commands/card/card-get.spec.ts +++ b/src/m365/pp/commands/card/card-get.spec.ts @@ -85,6 +85,13 @@ describe(commands.CARD_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/pp/commands/card/card-remove.spec.ts b/src/m365/pp/commands/card/card-remove.spec.ts index c3cbea51233..8fe80c9f698 100644 --- a/src/m365/pp/commands/card/card-remove.spec.ts +++ b/src/m365/pp/commands/card/card-remove.spec.ts @@ -26,7 +26,7 @@ describe(commands.CARD_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -52,18 +52,19 @@ describe(commands.CARD_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -101,7 +102,7 @@ describe(commands.CARD_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified card owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified card owned by the currently signed-in user when force option not passed', async () => { sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').callsFake(async () => envUrl); await command.action(logger, { @@ -110,21 +111,14 @@ describe(commands.CARD_REMOVE, () => { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified card owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified card owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { environmentName: validEnvironment, @@ -155,10 +149,8 @@ describe(commands.CARD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/card/card-remove.ts b/src/m365/pp/commands/card/card-remove.ts index 9c32c09ace8..c5d6118cd31 100644 --- a/src/m365/pp/commands/card/card-remove.ts +++ b/src/m365/pp/commands/card/card-remove.ts @@ -98,14 +98,9 @@ class PpCardRemoveCommand extends PowerPlatformCommand { await this.deleteCard(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove card '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove card '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.deleteCard(args); } } diff --git a/src/m365/pp/commands/chatbot/chatbot-get.spec.ts b/src/m365/pp/commands/chatbot/chatbot-get.spec.ts index fb1b5f58111..26c2b3f2d7a 100644 --- a/src/m365/pp/commands/chatbot/chatbot-get.spec.ts +++ b/src/m365/pp/commands/chatbot/chatbot-get.spec.ts @@ -87,6 +87,13 @@ describe(commands.CHATBOT_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/pp/commands/chatbot/chatbot-remove.spec.ts b/src/m365/pp/commands/chatbot/chatbot-remove.spec.ts index 111606b54e9..48d1483fc04 100644 --- a/src/m365/pp/commands/chatbot/chatbot-remove.spec.ts +++ b/src/m365/pp/commands/chatbot/chatbot-remove.spec.ts @@ -26,7 +26,7 @@ describe(commands.CHATBOT_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -52,18 +52,19 @@ describe(commands.CHATBOT_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -101,23 +102,18 @@ describe(commands.CHATBOT_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified chatbot owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified chatbot owned by the currently signed-in user when force option not passed', async () => { await command.action(logger, { options: { environmentName: validEnvironment, id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified chatbot owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified chatbot owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -150,10 +146,8 @@ describe(commands.CHATBOT_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { verbose: true, diff --git a/src/m365/pp/commands/chatbot/chatbot-remove.ts b/src/m365/pp/commands/chatbot/chatbot-remove.ts index 728887dd01f..736575a21d8 100644 --- a/src/m365/pp/commands/chatbot/chatbot-remove.ts +++ b/src/m365/pp/commands/chatbot/chatbot-remove.ts @@ -98,14 +98,9 @@ class PpChatbotRemoveCommand extends PowerPlatformCommand { await this.deleteChatbot(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove chatbot '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove chatbot '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.deleteChatbot(args); } } diff --git a/src/m365/pp/commands/dataverse/dataverse-table-remove.spec.ts b/src/m365/pp/commands/dataverse/dataverse-table-remove.spec.ts index 6ff56c7da60..9b7c2e3c658 100644 --- a/src/m365/pp/commands/dataverse/dataverse-table-remove.spec.ts +++ b/src/m365/pp/commands/dataverse/dataverse-table-remove.spec.ts @@ -22,7 +22,7 @@ describe(commands.DATAVERSE_TABLE_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -47,18 +47,19 @@ describe(commands.DATAVERSE_TABLE_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -75,23 +76,18 @@ describe(commands.DATAVERSE_TABLE_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the specified table owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified table owned by the currently signed-in user when force option not passed', async () => { await command.action(logger, { options: { environmentName: validEnvironment, name: validName } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified table owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified table owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { @@ -114,10 +110,8 @@ describe(commands.DATAVERSE_TABLE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/dataverse/dataverse-table-remove.ts b/src/m365/pp/commands/dataverse/dataverse-table-remove.ts index 4fc108b0f35..564264c2128 100644 --- a/src/m365/pp/commands/dataverse/dataverse-table-remove.ts +++ b/src/m365/pp/commands/dataverse/dataverse-table-remove.ts @@ -68,14 +68,9 @@ class PpDataverseTableRemoveCommand extends PowerPlatformCommand { await this.removeDataverseTable(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the dataverse table ${args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the dataverse table ${args.options.name}?` }); - if (result.continue) { + if (result) { await this.removeDataverseTable(args.options); } } diff --git a/src/m365/pp/commands/dataverse/dataverse-table-row-remove.spec.ts b/src/m365/pp/commands/dataverse/dataverse-table-row-remove.spec.ts index 903b7e46da2..856d7d07f27 100644 --- a/src/m365/pp/commands/dataverse/dataverse-table-row-remove.spec.ts +++ b/src/m365/pp/commands/dataverse/dataverse-table-row-remove.spec.ts @@ -29,7 +29,7 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -55,11 +55,12 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { @@ -67,7 +68,7 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { request.get, request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -106,7 +107,7 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified row from a dataverse table owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified row from a dataverse table owned by the currently signed-in user when force option not passed', async () => { sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').callsFake(async () => envUrl); await command.action(logger, { @@ -115,21 +116,14 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified row from a dataverse table owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified row from a dataverse table owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { environmentName: validEnvironment, @@ -150,10 +144,8 @@ describe(commands.DATAVERSE_TABLE_ROW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/dataverse/dataverse-table-row-remove.ts b/src/m365/pp/commands/dataverse/dataverse-table-row-remove.ts index 8897f711029..c49e530effa 100644 --- a/src/m365/pp/commands/dataverse/dataverse-table-row-remove.ts +++ b/src/m365/pp/commands/dataverse/dataverse-table-row-remove.ts @@ -100,14 +100,9 @@ class PpDataverseTableRowRemoveCommand extends PowerPlatformCommand { await this.deleteTableRow(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove row '${args.options.id}' from table '${args.options.tableName || args.options.entitySetName}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove row '${args.options.id}' from table '${args.options.tableName || args.options.entitySetName}'?` }); - if (result.continue) { + if (result) { await this.deleteTableRow(logger, args); } } diff --git a/src/m365/pp/commands/solution/solution-publish.spec.ts b/src/m365/pp/commands/solution/solution-publish.spec.ts index bf1ad38889f..0f5c4858b5b 100644 --- a/src/m365/pp/commands/solution/solution-publish.spec.ts +++ b/src/m365/pp/commands/solution/solution-publish.spec.ts @@ -73,7 +73,7 @@ describe(commands.SOLUTION_PUBLISH, () => { request.post, request.get, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); diff --git a/src/m365/pp/commands/solution/solution-publisher-remove.spec.ts b/src/m365/pp/commands/solution/solution-publisher-remove.spec.ts index f5a51986604..08f53a316e1 100644 --- a/src/m365/pp/commands/solution/solution-publisher-remove.spec.ts +++ b/src/m365/pp/commands/solution/solution-publisher-remove.spec.ts @@ -26,7 +26,7 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -52,11 +52,12 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { @@ -64,7 +65,7 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { // request.get, request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -102,7 +103,7 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified publisher owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified publisher owned by the currently signed-in user when force option not passed', async () => { sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').callsFake(async () => envUrl); await command.action(logger, { @@ -111,11 +112,6 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -151,10 +147,8 @@ describe(commands.SOLUTION_PUBLISHER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/solution/solution-publisher-remove.ts b/src/m365/pp/commands/solution/solution-publisher-remove.ts index 35879b6f0d8..a570e8ba92b 100644 --- a/src/m365/pp/commands/solution/solution-publisher-remove.ts +++ b/src/m365/pp/commands/solution/solution-publisher-remove.ts @@ -98,14 +98,9 @@ class PpSolutionPublisherRemoveCommand extends PowerPlatformCommand { await this.deletePublisher(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove publisher '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove publisher '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.deletePublisher(args); } } diff --git a/src/m365/pp/commands/solution/solution-remove.spec.ts b/src/m365/pp/commands/solution/solution-remove.spec.ts index 2e3fbe0f7bf..ef7e0e4f503 100644 --- a/src/m365/pp/commands/solution/solution-remove.spec.ts +++ b/src/m365/pp/commands/solution/solution-remove.spec.ts @@ -26,7 +26,7 @@ describe(commands.SOLUTION_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogToStderrSpy: sinon.SinonSpy; before(() => { @@ -52,18 +52,19 @@ describe(commands.SOLUTION_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, powerPlatform.getDynamicsInstanceApiUrl, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -101,23 +102,18 @@ describe(commands.SOLUTION_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified solution owned by the currently signed-in user when confirm option not passed', async () => { + it('prompts before removing the specified solution owned by the currently signed-in user when force option not passed', async () => { await command.action(logger, { options: { environmentName: validEnvironment, id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified solution owned by the currently signed-in user when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified solution owned by the currently signed-in user when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { @@ -162,10 +158,8 @@ describe(commands.SOLUTION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/pp/commands/solution/solution-remove.ts b/src/m365/pp/commands/solution/solution-remove.ts index 743500f2c0a..4984d2b2e29 100644 --- a/src/m365/pp/commands/solution/solution-remove.ts +++ b/src/m365/pp/commands/solution/solution-remove.ts @@ -98,14 +98,9 @@ class PpSolutionRemoveCommand extends PowerPlatformCommand { await this.deleteSolution(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove solution '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove solution '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.deleteSolution(args); } } diff --git a/src/m365/purview/commands/retentionevent/retentionevent-remove.spec.ts b/src/m365/purview/commands/retentionevent/retentionevent-remove.spec.ts index 718b2f42611..92ed7d19ea6 100644 --- a/src/m365/purview/commands/retentionevent/retentionevent-remove.spec.ts +++ b/src/m365/purview/commands/retentionevent/retentionevent-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.RETENTIONEVENT_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -47,17 +47,18 @@ describe(commands.RETENTIONEVENT_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -93,23 +94,18 @@ describe(commands.RETENTIONEVENT_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified retention event when confirm option not passed', async () => { + it('prompts before removing the specified retention event when force option not passed', async () => { await command.action(logger, { options: { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified retention event when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified retention event when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -128,8 +124,8 @@ describe(commands.RETENTIONEVENT_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/purview/commands/retentionevent/retentionevent-remove.ts b/src/m365/purview/commands/retentionevent/retentionevent-remove.ts index cc61bcd206f..f728b2b2f6e 100644 --- a/src/m365/purview/commands/retentionevent/retentionevent-remove.ts +++ b/src/m365/purview/commands/retentionevent/retentionevent-remove.ts @@ -68,14 +68,9 @@ class PurviewRetentionEventRemoveCommand extends GraphCommand { await this.removeRetentionEvent(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retention event ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retention event ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeRetentionEvent(args.options); } } diff --git a/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.spec.ts b/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.spec.ts index 8d452419aba..207d3e6dd15 100644 --- a/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.spec.ts +++ b/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.RETENTIONEVENTTYPE_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -47,16 +47,17 @@ describe(commands.RETENTIONEVENTTYPE_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, request.delete ]); }); @@ -85,19 +86,14 @@ describe(commands.RETENTIONEVENTTYPE_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified retention event type when confirm option not passed', async () => { + it('prompts before removing the specified retention event type when force option not passed', async () => { await command.action(logger, { options: { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified retention event type when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified retention event type when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { id: validId } }); assert(deleteSpy.notCalled); @@ -112,8 +108,8 @@ describe(commands.RETENTIONEVENTTYPE_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: validId } }); }); diff --git a/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.ts b/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.ts index b0b24a35082..39c5582e56d 100644 --- a/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.ts +++ b/src/m365/purview/commands/retentioneventtype/retentioneventtype-remove.ts @@ -68,14 +68,9 @@ class PurviewRetentionEventTypeRemoveCommand extends GraphCommand { await this.removeRetentionEventType(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retention event type with id ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retention event type with id ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeRetentionEventType(args.options); } } diff --git a/src/m365/purview/commands/retentionlabel/retentionlabel-remove.spec.ts b/src/m365/purview/commands/retentionlabel/retentionlabel-remove.spec.ts index 37b28c8afd8..22a28f1429e 100644 --- a/src/m365/purview/commands/retentionlabel/retentionlabel-remove.spec.ts +++ b/src/m365/purview/commands/retentionlabel/retentionlabel-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.RETENTIONLABEL_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -47,17 +47,18 @@ describe(commands.RETENTIONLABEL_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -93,23 +94,18 @@ describe(commands.RETENTIONLABEL_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified retention label when confirm option not passed', async () => { + it('prompts before removing the specified retention label when force option not passed', async () => { await command.action(logger, { options: { id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified retention label when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified retention label when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -128,10 +124,8 @@ describe(commands.RETENTIONLABEL_REMOVE, () => { throw 'Invalid Request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/purview/commands/retentionlabel/retentionlabel-remove.ts b/src/m365/purview/commands/retentionlabel/retentionlabel-remove.ts index 1ddd0b04d11..d529eb6ca7e 100644 --- a/src/m365/purview/commands/retentionlabel/retentionlabel-remove.ts +++ b/src/m365/purview/commands/retentionlabel/retentionlabel-remove.ts @@ -68,14 +68,9 @@ class PurviewRetentionLabelRemoveCommand extends GraphCommand { await this.removeRetentionLabel(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retention label ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retention label ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeRetentionLabel(args); } } diff --git a/src/m365/search/commands/externalconnection/externalconnection-remove.spec.ts b/src/m365/search/commands/externalconnection/externalconnection-remove.spec.ts index 38edeee3ef3..210967f15d3 100644 --- a/src/m365/search/commands/externalconnection/externalconnection-remove.spec.ts +++ b/src/m365/search/commands/externalconnection/externalconnection-remove.spec.ts @@ -15,7 +15,7 @@ import command from './externalconnection-remove.js'; describe(commands.EXTERNALCONNECTION_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -23,6 +23,13 @@ describe(commands.EXTERNALCONNECTION_REMOVE, () => { sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); auth.service.connected = true; + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -39,18 +46,19 @@ describe(commands.EXTERNALCONNECTION_REMOVE, () => { } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -67,37 +75,27 @@ describe(commands.EXTERNALCONNECTION_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the specified external connection by id when confirm option not passed', async () => { + it('prompts before removing the specified external connection by id when force option not passed', async () => { await command.action(logger, { options: { id: "contosohr" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified external connection by name when confirm option not passed', async () => { + it('prompts before removing the specified external connection by name when force option not passed', async () => { await command.action(logger, { options: { name: "Contoso HR" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified external connection when confirm option not passed and prompt not confirmed (debug)', async () => { + it('aborts removing the specified external connection when force option not passed and prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { debug: true, id: "contosohr" } }); assert(postSpy.notCalled); @@ -115,10 +113,8 @@ describe(commands.EXTERNALCONNECTION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: "contosohr" } }); diff --git a/src/m365/search/commands/externalconnection/externalconnection-remove.ts b/src/m365/search/commands/externalconnection/externalconnection-remove.ts index e0b7f225f59..3bff902f754 100644 --- a/src/m365/search/commands/externalconnection/externalconnection-remove.ts +++ b/src/m365/search/commands/externalconnection/externalconnection-remove.ts @@ -88,14 +88,9 @@ class SearchExternalConnectionRemoveCommand extends GraphCommand { await this.removeExternalConnection(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the external connection '${args.options.id || args.options.name}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the external connection '${args.options.id || args.options.name}'?` }); - if (result.continue) { + if (result) { await this.removeExternalConnection(args); } } diff --git a/src/m365/spo/commands/app/app-deploy.spec.ts b/src/m365/spo/commands/app/app-deploy.spec.ts index 37d8bbf49cf..7a4d833efa6 100644 --- a/src/m365/spo/commands/app/app-deploy.spec.ts +++ b/src/m365/spo/commands/app/app-deploy.spec.ts @@ -54,7 +54,7 @@ describe(commands.APP_DEPLOY, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); diff --git a/src/m365/spo/commands/app/app-remove.spec.ts b/src/m365/spo/commands/app/app-remove.spec.ts index b320304ddde..2f4d44a3d5a 100644 --- a/src/m365/spo/commands/app/app-remove.spec.ts +++ b/src/m365/spo/commands/app/app-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -44,11 +44,12 @@ describe(commands.APP_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(request, 'get').resolves({ "CorporateCatalogUrl": "https://contoso.sharepoint.com/sites/apps" }); }); @@ -56,7 +57,7 @@ describe(commands.APP_REMOVE, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -157,17 +158,12 @@ describe(commands.APP_REMOVE, () => { it('prompts before removing an app when confirmation argument not passed', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing app when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); }); @@ -193,8 +189,8 @@ describe(commands.APP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/app/app-remove.ts b/src/m365/spo/commands/app/app-remove.ts index b9c71d43f3d..6309444b83d 100644 --- a/src/m365/spo/commands/app/app-remove.ts +++ b/src/m365/spo/commands/app/app-remove.ts @@ -122,14 +122,9 @@ class SpoAppRemoveCommand extends SpoAppBaseCommand { await removeApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the app ${args.options.id} from the app catalog?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the app ${args.options.id} from the app catalog?` }); - if (result.continue) { + if (result) { await removeApp(); } } diff --git a/src/m365/spo/commands/app/app-retract.spec.ts b/src/m365/spo/commands/app/app-retract.spec.ts index 6868daf8aa1..08325ced387 100644 --- a/src/m365/spo/commands/app/app-retract.spec.ts +++ b/src/m365/spo/commands/app/app-retract.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_RETRACT, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -44,11 +44,12 @@ describe(commands.APP_RETRACT, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(request, 'get').resolves({ "CorporateCatalogUrl": "https://contoso.sharepoint.com/sites/apps" }); }); @@ -56,7 +57,7 @@ describe(commands.APP_RETRACT, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -184,20 +185,13 @@ describe(commands.APP_RETRACT, () => { it('prompts before retracting an app when confirmation argument not passed', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts retracting app when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); }); @@ -217,10 +211,8 @@ describe(commands.APP_RETRACT, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', appCatalogUrl: 'https://contoso.sharepoint.com' } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/app/app-retract.ts b/src/m365/spo/commands/app/app-retract.ts index 8a92f7c5b29..faef326d1c7 100644 --- a/src/m365/spo/commands/app/app-retract.ts +++ b/src/m365/spo/commands/app/app-retract.ts @@ -121,14 +121,9 @@ class SpoAppRetractCommand extends SpoAppBaseCommand { await retractApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to retract the app ${args.options.id} from the app catalog?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to retract the app ${args.options.id} from the app catalog?` }); - if (result.continue) { + if (result) { await retractApp(); } } diff --git a/src/m365/spo/commands/app/app-uninstall.spec.ts b/src/m365/spo/commands/app/app-uninstall.spec.ts index 172548a691c..d60f32bbc17 100644 --- a/src/m365/spo/commands/app/app-uninstall.spec.ts +++ b/src/m365/spo/commands/app/app-uninstall.spec.ts @@ -18,7 +18,7 @@ describe(commands.APP_UNINSTALL, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,16 +43,17 @@ describe(commands.APP_UNINSTALL, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; requests = []; - promptOptions = undefined; }); afterEach(() => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); }); after(() => { @@ -166,17 +167,12 @@ describe(commands.APP_UNINSTALL, () => { it('prompts before uninstalling an app when confirmation argument not passed', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', siteUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing property when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', siteUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); }); @@ -201,8 +197,8 @@ describe(commands.APP_UNINSTALL, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', siteUrl: 'https://contoso.sharepoint.com' } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/app/app-uninstall.ts b/src/m365/spo/commands/app/app-uninstall.ts index cf47dca3507..e5d67c76255 100644 --- a/src/m365/spo/commands/app/app-uninstall.ts +++ b/src/m365/spo/commands/app/app-uninstall.ts @@ -108,14 +108,9 @@ class SpoAppUninstallCommand extends SpoCommand { await uninstallApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to uninstall the app ${args.options.id} from site ${args.options.siteUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to uninstall the app ${args.options.id} from site ${args.options.siteUrl}?` }); - if (result.continue) { + if (result) { await uninstallApp(); } } diff --git a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.spec.ts b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.spec.ts index b9484661b23..9a1cfc1438a 100644 --- a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.spec.ts +++ b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.APPLICATIONCUSTOMIZER_REMOVE, () => { const id = '14125658-a9bc-4ddf-9c75-1b5767c9a337'; const clientSideComponentId = '015e0fcf-fe9d-4037-95af-0a4776cdfbb4'; const title = 'SiteGuidedTour'; - let promptOptions: any; + let promptIssued: boolean = false; let log: any[]; let logger: Logger; let requests: any[]; @@ -118,6 +118,13 @@ describe(commands.APPLICATIONCUSTOMIZER_REMOVE, () => { sinon.stub(session, 'getId').callsFake(() => ''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -134,18 +141,19 @@ describe(commands.APPLICATIONCUSTOMIZER_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -200,16 +208,12 @@ describe(commands.APPLICATIONCUSTOMIZER_REMOVE, () => { it('should prompt before removing application customizer when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, id: id } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing application customizer when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: webUrl, id: id } }); assert(requests.length === 0); }); @@ -316,8 +320,8 @@ describe(commands.APPLICATIONCUSTOMIZER_REMOVE, () => { }); const deleteCallsSpy: sinon.SinonStub = defaultDeleteCallsStub(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { verbose: true, id: id, webUrl: webUrl, scope: 'Web' } } as any); assert(deleteCallsSpy.calledOnce); diff --git a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.ts b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.ts index c52496a7673..791c4f765fd 100644 --- a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.ts +++ b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-remove.ts @@ -109,14 +109,9 @@ class SpoApplicationCustomizerRemoveCommand extends SpoCommand { return await this.removeApplicationCustomizer(logger, args.options); } - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the application customizer '${args.options.clientSideComponentId || args.options.title || args.options.id}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the application customizer '${args.options.clientSideComponentId || args.options.title || args.options.id}'?` }); - if (result.continue) { + if (result) { await this.removeApplicationCustomizer(logger, args.options); } } diff --git a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-set.spec.ts b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-set.spec.ts index a08e3730848..7fa92b673e6 100644 --- a/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-set.spec.ts +++ b/src/m365/spo/commands/applicationcustomizer/applicationcustomizer-set.spec.ts @@ -117,6 +117,13 @@ describe(commands.APPLICATIONCUSTOMIZER_SET, () => { sinon.stub(session, 'getId').callsFake(() => ''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/cdn/cdn-origin-remove.spec.ts b/src/m365/spo/commands/cdn/cdn-origin-remove.spec.ts index 6e3fb317b5c..5e3e13b14bf 100644 --- a/src/m365/spo/commands/cdn/cdn-origin-remove.spec.ts +++ b/src/m365/spo/commands/cdn/cdn-origin-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.CDN_ORIGIN_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -68,15 +68,16 @@ describe(commands.CDN_ORIGIN_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); }); after(() => { @@ -152,26 +153,21 @@ describe(commands.CDN_ORIGIN_REMOVE, () => { it('prompts before removing CDN origin when confirmation argument not passed', async () => { await command.action(logger, { options: { debug: true, origin: '*/cdn' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing CDN origin when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, origin: '*/cdn' } }); assert(requests.length === 0); }); it('removes CDN origin when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, origin: '*/cdn' } }); }); diff --git a/src/m365/spo/commands/cdn/cdn-origin-remove.ts b/src/m365/spo/commands/cdn/cdn-origin-remove.ts index 8bb4030b896..e8aad26e2b0 100644 --- a/src/m365/spo/commands/cdn/cdn-origin-remove.ts +++ b/src/m365/spo/commands/cdn/cdn-origin-remove.ts @@ -115,14 +115,9 @@ class SpoCdnOriginRemoveCommand extends SpoCommand { await removeCdnOrigin(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to delete the ${args.options.origin} CDN origin?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to delete the ${args.options.origin} CDN origin?` }); - if (result.continue) { + if (result) { await removeCdnOrigin(); } } diff --git a/src/m365/spo/commands/commandset/commandset-get.spec.ts b/src/m365/spo/commands/commandset/commandset-get.spec.ts index 3c8c336ce16..5234c090d15 100644 --- a/src/m365/spo/commands/commandset/commandset-get.spec.ts +++ b/src/m365/spo/commands/commandset/commandset-get.spec.ts @@ -35,6 +35,13 @@ describe(commands.COMMANDSET_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/commandset/commandset-remove.spec.ts b/src/m365/spo/commands/commandset/commandset-remove.spec.ts index 7179cb7cbe9..52a15f5fb40 100644 --- a/src/m365/spo/commands/commandset/commandset-remove.spec.ts +++ b/src/m365/spo/commands/commandset/commandset-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.COMMANDSET_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; //#region Mocked Responses const validUrl = 'https://contoso.sharepoint.com'; const validId = 'e7000aef-f756-4997-9420-01cc84f9ac9c'; @@ -135,11 +135,12 @@ describe(commands.COMMANDSET_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -147,7 +148,7 @@ describe(commands.COMMANDSET_REMOVE, () => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); @@ -200,25 +201,20 @@ describe(commands.COMMANDSET_REMOVE, () => { assert.notStrictEqual(actual, true); }); - it('prompts before removing the specified commandset when confirm option not passed', async () => { + it('prompts before removing the specified commandset when force option not passed', async () => { await command.action(logger, { options: { webUrl: validUrl, id: validId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified commandset when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified commandset when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -360,8 +356,8 @@ describe(commands.COMMANDSET_REMOVE, () => { throw `Invalid request`; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.doesNotReject(command.action(logger, { options: { @@ -389,8 +385,8 @@ describe(commands.COMMANDSET_REMOVE, () => { throw `Invalid request`; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.doesNotReject(command.action(logger, { options: { diff --git a/src/m365/spo/commands/commandset/commandset-remove.ts b/src/m365/spo/commands/commandset/commandset-remove.ts index 461bcb43fd1..49c80f55b69 100644 --- a/src/m365/spo/commands/commandset/commandset-remove.ts +++ b/src/m365/spo/commands/commandset/commandset-remove.ts @@ -112,14 +112,9 @@ class SpoCommandSetRemoveCommand extends SpoCommand { await this.deleteCommandset(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove command set '${args.options.clientSideComponentId || args.options.title || args.options.id}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove command set '${args.options.clientSideComponentId || args.options.title || args.options.id}'?` }); - if (result.continue) { + if (result) { await this.deleteCommandset(args); } } diff --git a/src/m365/spo/commands/contenttype/contenttype-field-remove.spec.ts b/src/m365/spo/commands/contenttype/contenttype-field-remove.spec.ts index 4df90dc9756..40663161fbf 100644 --- a/src/m365/spo/commands/contenttype/contenttype-field-remove.spec.ts +++ b/src/m365/spo/commands/contenttype/contenttype-field-remove.spec.ts @@ -30,7 +30,7 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const getStubCalls = async (opts: any) => { if ((opts.url as string).indexOf(`_api/site?$select=Id`) > -1) { @@ -163,17 +163,18 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; loggerLogSpy = sinon.spy(logger, 'log'); (command as any).requestDigest = ''; (command as any).webId = ''; (command as any).siteId = ''; (command as any).listId = ''; (command as any).fieldLinkId = ''; - promptOptions = undefined; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -181,7 +182,7 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -237,11 +238,6 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { force: false } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -249,8 +245,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: WEB_URL, contentTypeId: CONTENT_TYPE_ID, fieldLinkId: FIELD_LINK_ID, @@ -263,8 +259,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -287,10 +283,6 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { debug: true } } as any); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -298,8 +290,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -335,19 +327,14 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { updateChildContentTypes: true } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('removes the field link from web content type with update child content types - prompt: confirmed', async () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -362,8 +349,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -387,11 +374,6 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { debug: true } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -399,8 +381,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -417,8 +399,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -483,11 +465,6 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { webUrl: WEB_URL, listTitle: LIST_TITLE, contentTypeId: LIST_CONTENT_TYPE_ID, fieldLinkId: FIELD_LINK_ID } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -496,8 +473,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -514,8 +491,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); command.action(logger, { options: { @@ -553,11 +530,6 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { debug: true } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -565,8 +537,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -582,8 +554,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -599,8 +571,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -615,8 +587,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); const postCallbackStub = sinon.stub(request, 'post').callsFake(postStubSuccCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); command.action(logger, { options: { @@ -654,8 +626,8 @@ describe(commands.CONTENTTYPE_FIELD_REMOVE, () => { sinon.stub(request, 'get').callsFake(getStubCalls); sinon.stub(request, 'post').callsFake(postStubFailedCalls); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { diff --git a/src/m365/spo/commands/contenttype/contenttype-field-remove.ts b/src/m365/spo/commands/contenttype/contenttype-field-remove.ts index 9abb30a5710..81b6b403705 100644 --- a/src/m365/spo/commands/contenttype/contenttype-field-remove.ts +++ b/src/m365/spo/commands/contenttype/contenttype-field-remove.ts @@ -202,14 +202,9 @@ class SpoContentTypeFieldRemoveCommand extends SpoCommand { await removeFieldLink(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the column ${args.options.fieldLinkId} from content type ${args.options.contentTypeId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the column ${args.options.fieldLinkId} from content type ${args.options.contentTypeId}?` }); - if (result.continue) { + if (result) { await removeFieldLink(); } } diff --git a/src/m365/spo/commands/contenttype/contenttype-remove.spec.ts b/src/m365/spo/commands/contenttype/contenttype-remove.spec.ts index cb9399a9429..d9133348b03 100644 --- a/src/m365/spo/commands/contenttype/contenttype-remove.spec.ts +++ b/src/m365/spo/commands/contenttype/contenttype-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.CONTENTTYPE_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -43,11 +43,12 @@ describe(commands.CONTENTTYPE_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -55,7 +56,7 @@ describe(commands.CONTENTTYPE_REMOVE, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -85,11 +86,6 @@ describe(commands.CONTENTTYPE_REMOVE, () => { await command.action(logger, { options: { debug: true, verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', id: '0x0100558D85B7216F6A489A499DB361E1AE2F', force: false } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -104,8 +100,8 @@ describe(commands.CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -129,10 +125,8 @@ describe(commands.CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, @@ -163,11 +157,6 @@ describe(commands.CONTENTTYPE_REMOVE, () => { }); await command.action(logger, { options: { debug: true, verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', name: 'TestContentType', force: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -190,8 +179,8 @@ describe(commands.CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, verbose: false, webUrl: 'https://contoso.sharepoint.com/sites/portal', name: 'TestContentType', force: false } }); assert(getCallbackStub.called); @@ -215,8 +204,8 @@ describe(commands.CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/portal', name: 'TestContentType', force: false } }); assert(postCallbackStub.notCalled); diff --git a/src/m365/spo/commands/contenttype/contenttype-remove.ts b/src/m365/spo/commands/contenttype/contenttype-remove.ts index 99f3c6ec79a..5e2f3c9e537 100644 --- a/src/m365/spo/commands/contenttype/contenttype-remove.ts +++ b/src/m365/spo/commands/contenttype/contenttype-remove.ts @@ -147,9 +147,9 @@ class SpoContentTypeRemoveCommand extends SpoCommand { await removeContentType(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ type: 'confirm', name: 'continue', default: false, message: `Are you sure you want to remove the content type ${args.options.id || args.options.name}?` }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the content type ${args.options.id || args.options.name}?` }); - if (result.continue) { + if (result) { await removeContentType(); } } diff --git a/src/m365/spo/commands/customaction/customaction-clear.spec.ts b/src/m365/spo/commands/customaction/customaction-clear.spec.ts index 28b03c9f379..9fe530ec153 100644 --- a/src/m365/spo/commands/customaction/customaction-clear.spec.ts +++ b/src/m365/spo/commands/customaction/customaction-clear.spec.ts @@ -19,7 +19,7 @@ describe(commands.CUSTOMACTION_CLEAR, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const defaultPostCallsStub = (): sinon.SinonStub => { return sinon.stub(request, 'post').callsFake(async (opts) => { // fakes clear custom actions success (site) @@ -60,18 +60,19 @@ describe(commands.CUSTOMACTION_CLEAR, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -104,11 +105,6 @@ describe(commands.CUSTOMACTION_CLEAR, () => { it('should prompt before clearing custom actions when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -116,8 +112,8 @@ describe(commands.CUSTOMACTION_CLEAR, () => { it('should abort custom actions clear when prompt not confirmed', async () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com' } } as any); assert(postCallsSpy.notCalled); }); @@ -126,8 +122,8 @@ describe(commands.CUSTOMACTION_CLEAR, () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); const clearScopedCustomActionsSpy = sinon.spy((command as any), 'clearScopedCustomActions'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); try { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com' } } as any); diff --git a/src/m365/spo/commands/customaction/customaction-clear.ts b/src/m365/spo/commands/customaction/customaction-clear.ts index 2067c3d504c..84f3e171015 100644 --- a/src/m365/spo/commands/customaction/customaction-clear.ts +++ b/src/m365/spo/commands/customaction/customaction-clear.ts @@ -97,14 +97,9 @@ class SpoCustomActionClearCommand extends SpoCommand { await clearCustomActions(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to clear all the user custom actions with scope ${chalk.yellow(args.options.scope || 'All')}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to clear all the user custom actions with scope ${chalk.yellow(args.options.scope || 'All')}?` }); - if (result.continue) { + if (result) { await clearCustomActions(); } } diff --git a/src/m365/spo/commands/customaction/customaction-get.spec.ts b/src/m365/spo/commands/customaction/customaction-get.spec.ts index 16811f4857f..8a84cb3dea5 100644 --- a/src/m365/spo/commands/customaction/customaction-get.spec.ts +++ b/src/m365/spo/commands/customaction/customaction-get.spec.ts @@ -70,6 +70,13 @@ describe(commands.CUSTOMACTION_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/customaction/customaction-remove.spec.ts b/src/m365/spo/commands/customaction/customaction-remove.spec.ts index 3e580184b73..b6a2ffc014f 100644 --- a/src/m365/spo/commands/customaction/customaction-remove.spec.ts +++ b/src/m365/spo/commands/customaction/customaction-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.CUSTOMACTION_REMOVE, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; const defaultPostCallsStub = (): sinon.SinonStub => { return sinon.stub(request, 'post').callsFake(async (opts) => { @@ -65,12 +65,12 @@ describe(commands.CUSTOMACTION_REMOVE, () => { loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -79,7 +79,7 @@ describe(commands.CUSTOMACTION_REMOVE, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue, Cli.handleMultipleResultsFound ]); @@ -244,10 +244,8 @@ describe(commands.CUSTOMACTION_REMOVE, () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); const removeScopedCustomActionSpy = sinon.spy((command as any), 'removeScopedCustomAction'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); try { await command.action(logger, { options: { title: 'Places', webUrl: 'https://contoso.sharepoint.com' } } as any); @@ -297,11 +295,6 @@ describe(commands.CUSTOMACTION_REMOVE, () => { it('should prompt before removing custom action when confirmation argument not passed', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -309,8 +302,8 @@ describe(commands.CUSTOMACTION_REMOVE, () => { it('should abort custom action remove when prompt not confirmed', async () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } } as any); assert(postCallsSpy.notCalled); @@ -320,8 +313,8 @@ describe(commands.CUSTOMACTION_REMOVE, () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); const removeScopedCustomActionSpy = sinon.spy((command as any), 'removeScopedCustomAction'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); try { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } } as any); @@ -372,8 +365,8 @@ describe(commands.CUSTOMACTION_REMOVE, () => { const postCallsSpy: sinon.SinonStub = defaultPostCallsStub(); const removeScopedCustomActionSpy = sinon.spy((command as any), 'removeScopedCustomAction'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); try { await command.action(logger, { options: { title: 'Places', webUrl: 'https://contoso.sharepoint.com' } } as any); diff --git a/src/m365/spo/commands/customaction/customaction-remove.ts b/src/m365/spo/commands/customaction/customaction-remove.ts index 4cd1458ebad..80b45a43c97 100644 --- a/src/m365/spo/commands/customaction/customaction-remove.ts +++ b/src/m365/spo/commands/customaction/customaction-remove.ts @@ -124,14 +124,9 @@ class SpoCustomActionRemoveCommand extends SpoCommand { await removeCustomAction(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the ${args.options.id} user custom action?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the ${args.options.id} user custom action?` }); - if (result.continue) { + if (result) { await removeCustomAction(); } } diff --git a/src/m365/spo/commands/eventreceiver/eventreceiver-get.spec.ts b/src/m365/spo/commands/eventreceiver/eventreceiver-get.spec.ts index 07a465fe074..49fcbe42a15 100644 --- a/src/m365/spo/commands/eventreceiver/eventreceiver-get.spec.ts +++ b/src/m365/spo/commands/eventreceiver/eventreceiver-get.spec.ts @@ -41,6 +41,13 @@ describe(commands.EVENTRECEIVER_GET, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/eventreceiver/eventreceiver-remove.spec.ts b/src/m365/spo/commands/eventreceiver/eventreceiver-remove.spec.ts index 5c11ed7f865..18a7a449117 100644 --- a/src/m365/spo/commands/eventreceiver/eventreceiver-remove.spec.ts +++ b/src/m365/spo/commands/eventreceiver/eventreceiver-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const eventReceiverResponse = JSON.stringify( { @@ -57,18 +57,18 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { }; (command as any).items = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ Cli.executeCommandWithOutput, - Cli.prompt, + Cli.promptForConfirmation, request.delete ]); }); @@ -146,15 +146,9 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { assert.notStrictEqual(actual, true); }); - it('prompts before removing the event receiver when confirm option not passed', async () => { + it('prompts before removing the event receiver when force option not passed', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', scope: 'site', name: 'PnP Test Receiver' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); }); @@ -195,8 +189,8 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { stdout: eventReceiverResponse, stderr: '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', scope: 'site', name: 'PnP Test Receiver' } }); assert(requestDeleteStub.called); @@ -216,8 +210,8 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { stderr: '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', name: 'PnP Test Receiver', listUrl: '/sites/portal/Lists/rerlist' } }); assert(requestDeleteStub.called); @@ -237,8 +231,8 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { stderr: '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', name: 'PnP Test Receiver', listId: '8fccab0d-78e5-4037-a6a7-0168f9359cd4' } }); assert(requestDeleteStub.called); @@ -258,8 +252,8 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { stderr: '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', scope: 'site', id: '625b1f4c-2869-457f-8b41-bed72059bb2b' } }); assert(requestDeleteStub.called); @@ -279,8 +273,8 @@ describe(commands.EVENTRECEIVER_REMOVE, () => { stderr: '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/portal', listTitle: 'Documents', name: 'PnP Test Receiver' } }); assert(requestDeleteStub.called); diff --git a/src/m365/spo/commands/eventreceiver/eventreceiver-remove.ts b/src/m365/spo/commands/eventreceiver/eventreceiver-remove.ts index 60849f75e98..7c1914c3adf 100644 --- a/src/m365/spo/commands/eventreceiver/eventreceiver-remove.ts +++ b/src/m365/spo/commands/eventreceiver/eventreceiver-remove.ts @@ -127,14 +127,9 @@ class SpoEventreceiverRemoveCommand extends SpoCommand { await this.removeEventReceiver(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove event receiver with ${args.options.id ? `id ${args.options.id}` : `name ${args.options.name}`}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove event receiver with ${args.options.id ? `id ${args.options.id}` : `name ${args.options.name}`}?` }); - if (result.continue) { + if (result) { await this.removeEventReceiver(args.options); } } diff --git a/src/m365/spo/commands/field/field-remove.spec.ts b/src/m365/spo/commands/field/field-remove.spec.ts index 799bbd6edb4..0adcaed88bb 100644 --- a/src/m365/spo/commands/field/field-remove.spec.ts +++ b/src/m365/spo/commands/field/field-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.FIELD_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -45,11 +45,13 @@ describe(commands.FIELD_REMOVE, () => { } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + promptIssued = false; + requests = []; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -58,7 +60,7 @@ describe(commands.FIELD_REMOVE, () => { sinonUtil.restore([ request.post, request.get, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -78,48 +80,33 @@ describe(commands.FIELD_REMOVE, () => { it('prompts before removing field when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing field when confirmation argument not passed (title)', async () => { await command.action(logger, { options: { title: 'myfield1', webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing list column when confirmation argument not passed', async () => { await command.action(logger, { options: { title: 'myfield1', webUrl: 'https://contoso.sharepoint.com', listTitle: 'My List' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing field when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); }); it('aborts removing field when prompt not confirmed and passing the group parameter', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { group: 'MyGroup', webUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); @@ -140,8 +127,8 @@ describe(commands.FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } })); let correctRequestIssued = false; requests.forEach(r => { @@ -212,8 +199,8 @@ describe(commands.FIELD_REMOVE, () => { }); it('calls group and deletes two fields and asks for confirmation', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getStub = sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/sites/portal/_api/web/GetList(\'%2Fsites%2Fportal%2FLists%2FEvents\')/fields`) { diff --git a/src/m365/spo/commands/field/field-remove.ts b/src/m365/spo/commands/field/field-remove.ts index d11ac977170..737e32e82c9 100644 --- a/src/m365/spo/commands/field/field-remove.ts +++ b/src/m365/spo/commands/field/field-remove.ts @@ -206,14 +206,9 @@ class SpoFieldRemoveCommand extends SpoCommand { else { const confirmMessage: string = `Are you sure you want to remove the ${args.options.group ? 'fields' : 'field'} ${args.options.id || args.options.title || 'from group ' + args.options.group} ${messageEnd}?`; - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: confirmMessage - }); + const result = await Cli.promptForConfirmation({ message: confirmMessage }); - if (result.continue) { + if (result) { await prepareRemoval(); } } diff --git a/src/m365/spo/commands/file/file-checkout-undo.spec.ts b/src/m365/spo/commands/file/file-checkout-undo.spec.ts index 668e7c6c06f..05cc2a034d2 100644 --- a/src/m365/spo/commands/file/file-checkout-undo.spec.ts +++ b/src/m365/spo/commands/file/file-checkout-undo.spec.ts @@ -23,7 +23,7 @@ describe(commands.FILE_CHECKOUT_UNDO, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,16 +47,18 @@ describe(commands.FILE_CHECKOUT_UNDO, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -81,8 +83,8 @@ describe(commands.FILE_CHECKOUT_UNDO, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: webUrl, fileId: fileId, verbose: true } }); assert(postStub.called); @@ -138,21 +140,14 @@ describe(commands.FILE_CHECKOUT_UNDO, () => { it('prompts before undoing checkout when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, fileId: fileId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts undoing checkout when prompt not confirmed', async () => { const postStub = sinon.stub(request, 'post').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: webUrl, id: fileId } }); assert(postStub.notCalled); }); diff --git a/src/m365/spo/commands/file/file-checkout-undo.ts b/src/m365/spo/commands/file/file-checkout-undo.ts index c2acc6ccaf4..8614b278f23 100644 --- a/src/m365/spo/commands/file/file-checkout-undo.ts +++ b/src/m365/spo/commands/file/file-checkout-undo.ts @@ -123,14 +123,9 @@ class SpoFileCheckoutUndoCommand extends SpoCommand { await undoCheckout(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to undo the checkout for file ${args.options.fileId || args.options.fileUrl} ?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to undo the checkout for file ${args.options.fileId || args.options.fileUrl} ?` }); - if (result.continue) { + if (result) { await undoCheckout(); } } diff --git a/src/m365/spo/commands/file/file-copy.spec.ts b/src/m365/spo/commands/file/file-copy.spec.ts index a079a77983c..007b2f29db7 100644 --- a/src/m365/spo/commands/file/file-copy.spec.ts +++ b/src/m365/spo/commands/file/file-copy.spec.ts @@ -34,6 +34,13 @@ describe(commands.FILE_COPY, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/file/file-remove.spec.ts b/src/m365/spo/commands/file/file-remove.spec.ts index 1857132345c..f9954713f9a 100644 --- a/src/m365/spo/commands/file/file-remove.spec.ts +++ b/src/m365/spo/commands/file/file-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.FILE_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -46,17 +46,19 @@ describe(commands.FILE_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -90,29 +92,19 @@ describe(commands.FILE_REMOVE, () => { it('prompts before removing file when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: '0cd891ef-afce-4e55-b836-fce03286cccf' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing file when confirmation argument not passed (title)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: '0cd891ef-afce-4e55-b836-fce03286cccf' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing file when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: '0cd891ef-afce-4e55-b836-fce03286cccf' } }); assert(requests.length === 0); @@ -133,8 +125,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: '0cd891ef-afce-4e55-b836-fce03286cccf' } }); let correctRequestIssued = false; @@ -166,10 +158,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; requests.forEach(r => { @@ -200,10 +190,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; requests.forEach(r => { @@ -234,10 +222,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; requests.forEach(r => { @@ -268,10 +254,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; requests.forEach(r => { @@ -302,8 +286,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; @@ -335,10 +319,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; requests.forEach(r => { @@ -369,8 +351,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; @@ -402,8 +384,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; @@ -435,8 +417,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; @@ -468,8 +450,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: siteUrl, url: fileUrl } }); let correctRequestIssued = false; @@ -498,8 +480,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: '0cd891ef-afce-4e55-b836-fce03286cccf', recycle: true } }); let correctRequestIssued = false; @@ -528,8 +510,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', url: '0cd891ef-afce-4e55-b836-fce03286cccf' } }); let correctRequestIssued = false; @@ -558,8 +540,8 @@ describe(commands.FILE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', url: '0cd891ef-afce-4e55-b836-fce03286cccf', recycle: true } }); let correctRequestIssued = false; diff --git a/src/m365/spo/commands/file/file-remove.ts b/src/m365/spo/commands/file/file-remove.ts index ccd940b81a1..5ef0d7b9b6a 100644 --- a/src/m365/spo/commands/file/file-remove.ts +++ b/src/m365/spo/commands/file/file-remove.ts @@ -142,14 +142,9 @@ class SpoFileRemoveCommand extends SpoCommand { await removeFile(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to ${args.options.recycle ? 'recycle' : 'remove'} the file ${args.options.id || args.options.url} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to ${args.options.recycle ? 'recycle' : 'remove'} the file ${args.options.id || args.options.url} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeFile(); } } diff --git a/src/m365/spo/commands/file/file-retentionlabel-remove.spec.ts b/src/m365/spo/commands/file/file-retentionlabel-remove.spec.ts index cc26753c5f0..509c2527938 100644 --- a/src/m365/spo/commands/file/file-retentionlabel-remove.spec.ts +++ b/src/m365/spo/commands/file/file-retentionlabel-remove.spec.ts @@ -34,7 +34,7 @@ describe(commands.FILE_RETENTIONLABEL_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -59,17 +59,19 @@ describe(commands.FILE_RETENTIONLABEL_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.get, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput, cli.getSettingWithDefaultValue ]); @@ -90,19 +92,14 @@ describe(commands.FILE_RETENTIONLABEL_REMOVE, () => { it('prompts before removing retentionlabel from a file when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, fileUrl: fileUrl } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing file retention label when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -122,8 +119,8 @@ describe(commands.FILE_RETENTIONLABEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoListItemRetentionLabelRemoveCommand) { @@ -152,8 +149,8 @@ describe(commands.FILE_RETENTIONLABEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoListItemRetentionLabelRemoveCommand) { diff --git a/src/m365/spo/commands/file/file-retentionlabel-remove.ts b/src/m365/spo/commands/file/file-retentionlabel-remove.ts index 6c971e5d007..6a0ce3eb622 100644 --- a/src/m365/spo/commands/file/file-retentionlabel-remove.ts +++ b/src/m365/spo/commands/file/file-retentionlabel-remove.ts @@ -95,14 +95,9 @@ class SpoFileRetentionLabelRemoveCommand extends SpoCommand { await this.removeFileRetentionLabel(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retentionlabel from file ${args.options.fileId || args.options.fileUrl} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retentionlabel from file ${args.options.fileId || args.options.fileUrl} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeFileRetentionLabel(logger, args); } } diff --git a/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts b/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts index 607b349aaa9..d1e23759375 100644 --- a/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/file/file-roleassignment-remove.spec.ts @@ -29,7 +29,7 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -53,16 +53,17 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput, request.post ]); @@ -101,7 +102,7 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing role assignment from the file when confirm option not passed', async () => { + it('prompts before removing role assignment from the file when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -110,16 +111,11 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing role assignment from the file when confirm option is not passed and prompt not confirmed', async () => { + it('aborts removing role assignment from the file when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -143,8 +139,8 @@ describe(commands.FILE_ROLEASSIGNMENT_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-roleassignment-remove.ts b/src/m365/spo/commands/file/file-roleassignment-remove.ts index 7251080c91f..9ecd78e916a 100644 --- a/src/m365/spo/commands/file/file-roleassignment-remove.ts +++ b/src/m365/spo/commands/file/file-roleassignment-remove.ts @@ -151,14 +151,9 @@ class SpoFileRoleAssignmentRemoveCommand extends SpoCommand { await removeRoleAssignment(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove role assignment from file ${args.options.fileUrl || args.options.fileId} from site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove role assignment from file ${args.options.fileUrl || args.options.fileId} from site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeRoleAssignment(); } } diff --git a/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts b/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts index cdbca245d8c..aca0fe778f7 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-break.spec.ts @@ -23,7 +23,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,16 +47,17 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput, request.post ]); @@ -90,7 +91,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { assert.strictEqual(actual, true); }); - it('prompts before breaking role inheritance for the file when confirm option not passed', async () => { + it('prompts before breaking role inheritance for the file when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -98,16 +99,11 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts breaking role inheritance for the file when confirm option is not passed and prompt not confirmed', async () => { + it('aborts breaking role inheritance for the file when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -179,8 +175,8 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-roleinheritance-break.ts b/src/m365/spo/commands/file/file-roleinheritance-break.ts index e6e786ea2d0..92709fdc4f3 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-break.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-break.ts @@ -121,14 +121,9 @@ class SpoFileRoleInheritanceBreakCommand extends SpoCommand { await breakFileRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to break the role inheritance of file ${args.options.fileUrl || args.options.fileId} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to break the role inheritance of file ${args.options.fileUrl || args.options.fileId} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await breakFileRoleInheritance(); } } diff --git a/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts b/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts index 9b7cad55644..05a9c7f00dc 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-reset.spec.ts @@ -23,7 +23,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,16 +47,17 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, request.post ]); }); @@ -89,7 +90,7 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { assert.strictEqual(actual, true); }); - it('prompts before resetting role inheritance for the file when confirm option not passed', async () => { + it('prompts before resetting role inheritance for the file when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -97,16 +98,11 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts resetting role inheritance for the file when confirm option is not passed and prompt not confirmed', async () => { + it('aborts resetting role inheritance for the file when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -157,8 +153,8 @@ describe(commands.FILE_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-roleinheritance-reset.ts b/src/m365/spo/commands/file/file-roleinheritance-reset.ts index 300a9b514a9..c1de75f76c3 100644 --- a/src/m365/spo/commands/file/file-roleinheritance-reset.ts +++ b/src/m365/spo/commands/file/file-roleinheritance-reset.ts @@ -114,14 +114,9 @@ class SpoFileRoleInheritanceResetCommand extends SpoCommand { await resetFileRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to reset the role inheritance of file ${args.options.fileUrl || args.options.fileId} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to reset the role inheritance of file ${args.options.fileUrl || args.options.fileId} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await resetFileRoleInheritance(); } } diff --git a/src/m365/spo/commands/file/file-sharinglink-clear.spec.ts b/src/m365/spo/commands/file/file-sharinglink-clear.spec.ts index 16b5fe649d6..34712ce6714 100644 --- a/src/m365/spo/commands/file/file-sharinglink-clear.spec.ts +++ b/src/m365/spo/commands/file/file-sharinglink-clear.spec.ts @@ -35,7 +35,7 @@ describe(commands.FILE_SHARINGLINK_CLEAR, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -59,18 +59,19 @@ describe(commands.FILE_SHARINGLINK_CLEAR, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, request.get, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput ]); }); @@ -113,31 +114,27 @@ describe(commands.FILE_SHARINGLINK_CLEAR, () => { assert.strictEqual(actual, true); }); - it('aborts clearing the sharing links to a file when confirm option not passed and prompt not confirmed', async () => { + it('aborts clearing the sharing links to a file when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: webUrl, fileUrl: fileUrl } }); assert(postSpy.notCalled); }); - it('prompts before clearing the sharing links to a file when confirm option not passed', async () => { + it('prompts before clearing the sharing links to a file when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, fileId: fileId } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('clears sharing links from a specific file retrieved by url', async () => { const fileServerRelativeUrl: string = urlUtil.getServerRelativePath(webUrl, fileUrl); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/GetFileByServerRelativePath(decodedUrl='${formatting.encodeQueryParameter(fileServerRelativeUrl)}')?$select=SiteId,VroomItemId,VroomDriveId`) { @@ -167,8 +164,8 @@ describe(commands.FILE_SHARINGLINK_CLEAR, () => { }); it('clears sharing links of type anonymous from a specific file retrieved by id', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/GetFileById('${fileId}')?$select=SiteId,VroomItemId,VroomDriveId`) { @@ -198,8 +195,8 @@ describe(commands.FILE_SHARINGLINK_CLEAR, () => { }); it('throws error when file not found by id', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/GetFileById('${fileId}')?$select=SiteId,VroomItemId,VroomDriveId`) { diff --git a/src/m365/spo/commands/file/file-sharinglink-clear.ts b/src/m365/spo/commands/file/file-sharinglink-clear.ts index 43e7a756e04..a67d48f782e 100644 --- a/src/m365/spo/commands/file/file-sharinglink-clear.ts +++ b/src/m365/spo/commands/file/file-sharinglink-clear.ts @@ -129,14 +129,9 @@ class SpoFileSharingLinkClearCommand extends SpoCommand { await clearSharingLinks(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to clear the sharing links of file ${args.options.fileUrl || args.options.fileId}${args.options.scope ? ` with scope ${args.options.scope}` : ''}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to clear the sharing links of file ${args.options.fileUrl || args.options.fileId}${args.options.scope ? ` with scope ${args.options.scope}` : ''}?` }); - if (result.continue) { + if (result) { await clearSharingLinks(); } } diff --git a/src/m365/spo/commands/file/file-sharinglink-remove.spec.ts b/src/m365/spo/commands/file/file-sharinglink-remove.spec.ts index 65e1a482d19..4efbeb6faf1 100644 --- a/src/m365/spo/commands/file/file-sharinglink-remove.spec.ts +++ b/src/m365/spo/commands/file/file-sharinglink-remove.spec.ts @@ -31,7 +31,7 @@ describe(commands.FILE_SHARINGLINK_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -55,18 +55,19 @@ describe(commands.FILE_SHARINGLINK_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -98,7 +99,7 @@ describe(commands.FILE_SHARINGLINK_REMOVE, () => { assert.notStrictEqual(actual, true); }); - it('prompts before removing the specified sharing link to a file when confirm option not passed', async () => { + it('prompts before removing the specified sharing link to a file when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -107,19 +108,14 @@ describe(commands.FILE_SHARINGLINK_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified sharing link to a file when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified sharing link to a file when force option not passed and prompt not confirmed', async () => { const deleteSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -149,8 +145,8 @@ describe(commands.FILE_SHARINGLINK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-sharinglink-remove.ts b/src/m365/spo/commands/file/file-sharinglink-remove.ts index 710f1f3c626..a49b2b9ef50 100644 --- a/src/m365/spo/commands/file/file-sharinglink-remove.ts +++ b/src/m365/spo/commands/file/file-sharinglink-remove.ts @@ -115,14 +115,9 @@ class SpoFileSharingLinkRemoveCommand extends SpoCommand { await removeSharingLink(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove sharing link ${args.options.id} of file ${args.options.fileUrl || args.options.fileId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove sharing link ${args.options.id} of file ${args.options.fileUrl || args.options.fileId}?` }); - if (result.continue) { + if (result) { await removeSharingLink(); } } diff --git a/src/m365/spo/commands/file/file-version-clear.spec.ts b/src/m365/spo/commands/file/file-version-clear.spec.ts index 1f474a4b0f1..19629501b38 100644 --- a/src/m365/spo/commands/file/file-version-clear.spec.ts +++ b/src/m365/spo/commands/file/file-version-clear.spec.ts @@ -19,7 +19,7 @@ describe(commands.FILE_VERSION_CLEAR, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validWebUrl = "https://contoso.sharepoint.com"; const validFileUrl = "/Shared Documents/Document.docx"; const validFileId = "7a9b8bb6-d5c4-4de9-ab76-5210a7879e89"; @@ -47,17 +47,18 @@ describe(commands.FILE_VERSION_CLEAR, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -99,26 +100,21 @@ describe(commands.FILE_VERSION_CLEAR, () => { assert.strictEqual(actual, true); }); - it('prompts before removing all file history when confirm option not passed', async () => { + it('prompts before removing all file history when force option not passed', async () => { await command.action(logger, { options: { webUrl: validWebUrl, fileId: validFileId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing all file history when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing all file history when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -175,8 +171,8 @@ describe(commands.FILE_VERSION_CLEAR, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -196,8 +192,8 @@ describe(commands.FILE_VERSION_CLEAR, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-version-clear.ts b/src/m365/spo/commands/file/file-version-clear.ts index d2c64876e76..48fbe5d6188 100644 --- a/src/m365/spo/commands/file/file-version-clear.ts +++ b/src/m365/spo/commands/file/file-version-clear.ts @@ -90,14 +90,9 @@ class SpoFileVersionClearCommand extends SpoCommand { await this.clearVersions(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to delete all version history for file ${args.options.fileId || args.options.fileUrl}'?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to delete all version history for file ${args.options.fileId || args.options.fileUrl}'?` }); + + if (result) { await this.clearVersions(args); } } diff --git a/src/m365/spo/commands/file/file-version-remove.spec.ts b/src/m365/spo/commands/file/file-version-remove.spec.ts index cfc0bc91bea..01b3ad0e772 100644 --- a/src/m365/spo/commands/file/file-version-remove.spec.ts +++ b/src/m365/spo/commands/file/file-version-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.FILE_VERSION_REMOVE, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validWebUrl = "https://contoso.sharepoint.com"; const validFileUrl = "/Shared Documents/Document.docx"; const validFileId = "7a9b8bb6-d5c4-4de9-ab76-5210a7879e89"; @@ -48,17 +48,18 @@ describe(commands.FILE_VERSION_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -101,7 +102,7 @@ describe(commands.FILE_VERSION_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified version when confirm option not passed', async () => { + it('prompts before removing the specified version when force option not passed', async () => { await command.action(logger, { options: { webUrl: validWebUrl, @@ -109,19 +110,14 @@ describe(commands.FILE_VERSION_REMOVE, () => { fileId: validFileId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified version when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified version when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -181,8 +177,8 @@ describe(commands.FILE_VERSION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -203,8 +199,8 @@ describe(commands.FILE_VERSION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-version-remove.ts b/src/m365/spo/commands/file/file-version-remove.ts index a6012454ecc..e9df320b86c 100644 --- a/src/m365/spo/commands/file/file-version-remove.ts +++ b/src/m365/spo/commands/file/file-version-remove.ts @@ -99,14 +99,9 @@ class SpoFileVersionRemoveCommand extends SpoCommand { await this.removeVersion(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the version ${args.options.label} from file ${args.options.fileId || args.options.fileUrl}'?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the version ${args.options.label} from file ${args.options.fileId || args.options.fileUrl}'?` }); + + if (result) { await this.removeVersion(args); } } diff --git a/src/m365/spo/commands/file/file-version-restore.spec.ts b/src/m365/spo/commands/file/file-version-restore.spec.ts index 54f4d036d0f..45e79d3e0ea 100644 --- a/src/m365/spo/commands/file/file-version-restore.spec.ts +++ b/src/m365/spo/commands/file/file-version-restore.spec.ts @@ -19,7 +19,7 @@ describe(commands.FILE_VERSION_RESTORE, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const validWebUrl = "https://contoso.sharepoint.com"; const validFileUrl = "/Shared Documents/Document.docx"; const validFileId = "7a9b8bb6-d5c4-4de9-ab76-5210a7879e89"; @@ -48,17 +48,18 @@ describe(commands.FILE_VERSION_RESTORE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -101,7 +102,7 @@ describe(commands.FILE_VERSION_RESTORE, () => { assert.strictEqual(actual, true); }); - it('prompts before restoring the specified version when confirm option not passed', async () => { + it('prompts before restoring the specified version when force option not passed', async () => { await command.action(logger, { options: { webUrl: validWebUrl, @@ -109,19 +110,14 @@ describe(commands.FILE_VERSION_RESTORE, () => { fileId: validFileId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts restoring the specified version when confirm option not passed and prompt not confirmed', async () => { + it('aborts restoring the specified version when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -181,8 +177,8 @@ describe(commands.FILE_VERSION_RESTORE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -203,10 +199,8 @@ describe(commands.FILE_VERSION_RESTORE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/file/file-version-restore.ts b/src/m365/spo/commands/file/file-version-restore.ts index 1f5a335c7d9..97acfba7c8a 100644 --- a/src/m365/spo/commands/file/file-version-restore.ts +++ b/src/m365/spo/commands/file/file-version-restore.ts @@ -99,14 +99,9 @@ class SpoFileVersionRestoreCommand extends SpoCommand { await this.restoreVersion(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to restore the version ${args.options.label} from file ${args.options.fileId || args.options.fileUrl}'?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to restore the version ${args.options.label} from file ${args.options.fileId || args.options.fileUrl}'?` }); + + if (result) { await this.restoreVersion(args); } } diff --git a/src/m365/spo/commands/folder/folder-remove.spec.ts b/src/m365/spo/commands/folder/folder-remove.spec.ts index c5d2ed5ab74..7d6ecd87795 100644 --- a/src/m365/spo/commands/folder/folder-remove.spec.ts +++ b/src/m365/spo/commands/folder/folder-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.FOLDER_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; let stubPost: sinon.SinonStub; before(() => { @@ -52,17 +52,19 @@ describe(commands.FOLDER_REMOVE, () => { throw 'Invalid request'; }); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; requests = []; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -81,26 +83,20 @@ describe(commands.FOLDER_REMOVE, () => { it('prompts before removing folder when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', url: '/Shared Documents' } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing folder when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', url: '/Shared Documents' } }); assert(requests.length === 0); }); it('removes the folder when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -128,8 +124,8 @@ describe(commands.FOLDER_REMOVE, () => { }); it('should send params for remove request for sites/test1', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: @@ -146,8 +142,8 @@ describe(commands.FOLDER_REMOVE, () => { }); it('should send params for recycle request when recycle is set to true', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: @@ -179,8 +175,8 @@ describe(commands.FOLDER_REMOVE, () => { sinonUtil.restore(request.post); sinon.stub(request, 'post').rejects(error); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: diff --git a/src/m365/spo/commands/folder/folder-remove.ts b/src/m365/spo/commands/folder/folder-remove.ts index 3a3356e86e0..99fc997f3fc 100644 --- a/src/m365/spo/commands/folder/folder-remove.ts +++ b/src/m365/spo/commands/folder/folder-remove.ts @@ -77,14 +77,9 @@ class SpoFolderRemoveCommand extends SpoCommand { await this.removeFolder(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to ${args.options.recycle ? "recycle" : "remove"} the folder ${args.options.url} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to ${args.options.recycle ? "recycle" : "remove"} the folder ${args.options.url} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeFolder(logger, args.options); } } diff --git a/src/m365/spo/commands/folder/folder-retentionlabel-remove.spec.ts b/src/m365/spo/commands/folder/folder-retentionlabel-remove.spec.ts index 069b113be80..531114a1171 100644 --- a/src/m365/spo/commands/folder/folder-retentionlabel-remove.spec.ts +++ b/src/m365/spo/commands/folder/folder-retentionlabel-remove.spec.ts @@ -35,7 +35,7 @@ describe(commands.FOLDER_RETENTIONLABEL_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -60,17 +60,19 @@ describe(commands.FOLDER_RETENTIONLABEL_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.get, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput, cli.getSettingWithDefaultValue ]); @@ -91,19 +93,14 @@ describe(commands.FOLDER_RETENTIONLABEL_REMOVE, () => { it('prompts before removing retentionlabel from a folder when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, folderUrl: folderUrl } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing folder retention label when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { folderUrl: folderUrl, @@ -122,8 +119,8 @@ describe(commands.FOLDER_RETENTIONLABEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoListItemRetentionLabelRemoveCommand) { @@ -152,8 +149,8 @@ describe(commands.FOLDER_RETENTIONLABEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoListItemRetentionLabelRemoveCommand) { diff --git a/src/m365/spo/commands/folder/folder-retentionlabel-remove.ts b/src/m365/spo/commands/folder/folder-retentionlabel-remove.ts index aaaf2a3aa4b..2de0e5833c1 100644 --- a/src/m365/spo/commands/folder/folder-retentionlabel-remove.ts +++ b/src/m365/spo/commands/folder/folder-retentionlabel-remove.ts @@ -95,14 +95,9 @@ class SpoFolderRetentionLabelRemoveCommand extends SpoCommand { await this.removeFolderRetentionLabel(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retentionlabel from folder ${args.options.folderId || args.options.folderUrl} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retentionlabel from folder ${args.options.folderId || args.options.folderUrl} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeFolderRetentionLabel(logger, args); } } diff --git a/src/m365/spo/commands/folder/folder-roleassignment-remove.spec.ts b/src/m365/spo/commands/folder/folder-roleassignment-remove.spec.ts index 1106ec2336b..8a3798dc243 100644 --- a/src/m365/spo/commands/folder/folder-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/folder/folder-roleassignment-remove.spec.ts @@ -21,7 +21,7 @@ describe(commands.FOLDER_ROLEASSIGNMENT_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -47,10 +47,12 @@ describe(commands.FOLDER_ROLEASSIGNMENT_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -58,7 +60,7 @@ describe(commands.FOLDER_ROLEASSIGNMENT_REMOVE, () => { sinonUtil.restore([ request.post, Cli.executeCommandWithOutput, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -281,11 +283,6 @@ describe(commands.FOLDER_ROLEASSIGNMENT_REMOVE, () => { groupName: 'someGroup' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -308,8 +305,8 @@ describe(commands.FOLDER_ROLEASSIGNMENT_REMOVE, () => { throw new CommandError('Unknown case'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/spo/commands/folder/folder-roleassignment-remove.ts b/src/m365/spo/commands/folder/folder-roleassignment-remove.ts index 00d79271277..ae4a2746acf 100644 --- a/src/m365/spo/commands/folder/folder-roleassignment-remove.ts +++ b/src/m365/spo/commands/folder/folder-roleassignment-remove.ts @@ -131,14 +131,9 @@ class SpoFolderRoleAssignmentRemoveCommand extends SpoCommand { await removeRoleAssignment(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove a role assignment from the folder with url '${args.options.folderUrl}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove a role assignment from the folder with url '${args.options.folderUrl}'?` }); - if (result.continue) { + if (result) { await removeRoleAssignment(); } } diff --git a/src/m365/spo/commands/folder/folder-roleinheritance-break.spec.ts b/src/m365/spo/commands/folder/folder-roleinheritance-break.spec.ts index e976264a84d..d767f805ff5 100644 --- a/src/m365/spo/commands/folder/folder-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/folder/folder-roleinheritance-break.spec.ts @@ -23,7 +23,7 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,16 +47,17 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, request.post ]); }); @@ -84,7 +85,7 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { assert.strictEqual(actual, true); }); - it('prompts before breaking role inheritance for the folder when confirm option not passed', async () => { + it('prompts before breaking role inheritance for the folder when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -92,16 +93,11 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts breaking role inheritance for the folder when confirm option is not passed and prompt not confirmed', async () => { + it('aborts breaking role inheritance for the folder when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -144,8 +140,8 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -165,8 +161,8 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -185,8 +181,8 @@ describe(commands.FOLDER_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/folder/folder-roleinheritance-break.ts b/src/m365/spo/commands/folder/folder-roleinheritance-break.ts index 51939631cf0..02a72325234 100644 --- a/src/m365/spo/commands/folder/folder-roleinheritance-break.ts +++ b/src/m365/spo/commands/folder/folder-roleinheritance-break.ts @@ -100,14 +100,9 @@ class SpoFolderRoleInheritanceBreakCommand extends SpoCommand { await breakFolderRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to break the role inheritance of folder ${args.options.folderUrl} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to break the role inheritance of folder ${args.options.folderUrl} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await breakFolderRoleInheritance(); } } diff --git a/src/m365/spo/commands/folder/folder-roleinheritance-reset.spec.ts b/src/m365/spo/commands/folder/folder-roleinheritance-reset.spec.ts index 3b804517be8..c9c509a0c1c 100644 --- a/src/m365/spo/commands/folder/folder-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/folder/folder-roleinheritance-reset.spec.ts @@ -21,7 +21,7 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -45,16 +45,17 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, request.post ]); }); @@ -82,7 +83,7 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { assert.strictEqual(actual, true); }); - it('prompts before resetting role inheritance for the folder when confirm option not passed', async () => { + it('prompts before resetting role inheritance for the folder when force option not passed', async () => { await command.action(logger, { options: { webUrl: webUrl, @@ -90,16 +91,11 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts resetting role inheritance for the folder when confirm option is not passed and prompt not confirmed', async () => { + it('aborts resetting role inheritance for the folder when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -140,10 +136,8 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -162,8 +156,8 @@ describe(commands.FOLDER_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/folder/folder-roleinheritance-reset.ts b/src/m365/spo/commands/folder/folder-roleinheritance-reset.ts index 4181fdd9a3c..32cfc2b4ede 100644 --- a/src/m365/spo/commands/folder/folder-roleinheritance-reset.ts +++ b/src/m365/spo/commands/folder/folder-roleinheritance-reset.ts @@ -95,14 +95,9 @@ class SpoFolderRoleInheritanceResetCommand extends SpoCommand { await resetFolderRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to reset the role inheritance of folder ${args.options.folderUrl} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to reset the role inheritance of folder ${args.options.folderUrl} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await resetFolderRoleInheritance(); } } diff --git a/src/m365/spo/commands/group/group-member-remove.spec.ts b/src/m365/spo/commands/group/group-member-remove.spec.ts index d7f064ec917..90eb3bc015c 100644 --- a/src/m365/spo/commands/group/group-member-remove.spec.ts +++ b/src/m365/spo/commands/group/group-member-remove.spec.ts @@ -79,7 +79,7 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, Cli.executeCommandWithOutput, cli.getSettingWithDefaultValue ]); @@ -99,8 +99,8 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { }); it('Removes Azure AD group from SharePoint group using Azure AD Group Name', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoGroupMemberListCommand) { @@ -161,8 +161,8 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { }); it('Removes Azure AD group from SharePoint group using Azure AD Group ID and SharePoint Group ID', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(async (command): Promise => { if (command === spoGroupMemberListCommand) { @@ -368,7 +368,7 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('removes user from SharePoint group by groupId and userName with confirm option (debug)', async () => { + it('removes user from SharePoint group by groupId and userName with force option (debug)', async () => { const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { const loginName: string = `i:0#.f|membership|${userName}`; if (opts.url === `${webUrl}/_api/web/sitegroups/GetById('${groupId}')/users/removeByLoginName(@LoginName)?@LoginName='${formatting.encodeQueryParameter(loginName)}'`) { @@ -392,11 +392,9 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert(postStub.called); }); - it('removes user from SharePoint group by groupId and userName when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + it('removes user from SharePoint group by groupId and userName when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { const loginName: string = `i:0#.f|membership|${userName}`; @@ -420,11 +418,9 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert(postStub.called); }); - it('removes user from SharePoint group by groupId and userId when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + it('removes user from SharePoint group by groupId and userId when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/sitegroups/GetById('${groupId}')/users/removeById(${userId})`) { @@ -447,11 +443,9 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert(postStub.called); }); - it('removes user from SharePoint group by groupId and email when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + it('removes user from SharePoint group by groupId and email when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(Cli, 'executeCommandWithOutput').callsFake(() => Promise.resolve({ stdout: JSON.stringify(userInformation), @@ -480,7 +474,7 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert(postStub.called); }); - it('removes user from SharePoint group by groupName and userId with confirm option', async () => { + it('removes user from SharePoint group by groupName and userId with force option', async () => { const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `${webUrl}/_api/web/sitegroups/GetByName('${formatting.encodeQueryParameter(groupName)}')/users/removeById(${userId})`) { return UserRemovalJSONResponse; @@ -502,7 +496,7 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { assert(postStub.called); }); - it('removes user from SharePoint group by groupName and email with confirm option', async () => { + it('removes user from SharePoint group by groupName and email with force option', async () => { sinon.stub(Cli, 'executeCommandWithOutput').callsFake(() => Promise.resolve({ stdout: JSON.stringify(userInformation), stderr: '' @@ -532,10 +526,8 @@ describe(commands.GROUP_MEMBER_REMOVE, () => { it('aborts removing user from SharePoint group when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/group/group-member-remove.ts b/src/m365/spo/commands/group/group-member-remove.ts index c1c44d87da8..951badb2078 100644 --- a/src/m365/spo/commands/group/group-member-remove.ts +++ b/src/m365/spo/commands/group/group-member-remove.ts @@ -155,14 +155,9 @@ class SpoGroupMemberRemoveCommand extends SpoCommand { await this.removeUserfromSPGroup(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove user ${args.options.userName || args.options.userId || args.options.email || args.options.aadGroupId || args.options.aadGroupName} from the SharePoint group?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove user ${args.options.userName || args.options.userId || args.options.email || args.options.aadGroupId || args.options.aadGroupName} from the SharePoint group?` }); - if (result.continue) { + if (result) { await this.removeUserfromSPGroup(logger, args); } } diff --git a/src/m365/spo/commands/group/group-remove.spec.ts b/src/m365/spo/commands/group/group-remove.spec.ts index 6adb3d2df12..60aa7648493 100755 --- a/src/m365/spo/commands/group/group-remove.spec.ts +++ b/src/m365/spo/commands/group/group-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.GROUP_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -43,10 +43,12 @@ describe(commands.GROUP_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -54,7 +56,7 @@ describe(commands.GROUP_REMOVE, () => { sinonUtil.restore([ request.post, request.get, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -125,8 +127,8 @@ describe(commands.GROUP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/mysite', id: 7, debug: true } }); assert(requestPostSpy.called); @@ -156,20 +158,12 @@ describe(commands.GROUP_REMOVE, () => { it('prompts before removing group when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { id: 7, webUrl: 'https://contoso.sharepoint.com/mysite' } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing group when confirmation argument not passed (name)', async () => { await command.action(logger, { options: { name: 'Team Site Owners', webUrl: 'https://contoso.sharepoint.com/mysite' } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); diff --git a/src/m365/spo/commands/group/group-remove.ts b/src/m365/spo/commands/group/group-remove.ts index e5a94377352..e19c478f3b5 100755 --- a/src/m365/spo/commands/group/group-remove.ts +++ b/src/m365/spo/commands/group/group-remove.ts @@ -129,14 +129,9 @@ class SpoGroupRemoveCommand extends SpoCommand { await removeGroup(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the group ${args.options.id || args.options.name} from web ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the group ${args.options.id || args.options.name} from web ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeGroup(); } } diff --git a/src/m365/spo/commands/hidedefaultthemes/hidedefaultthemes-set.spec.ts b/src/m365/spo/commands/hidedefaultthemes/hidedefaultthemes-set.spec.ts index 49f47c9fa97..0b835f1c2d3 100644 --- a/src/m365/spo/commands/hidedefaultthemes/hidedefaultthemes-set.spec.ts +++ b/src/m365/spo/commands/hidedefaultthemes/hidedefaultthemes-set.spec.ts @@ -27,6 +27,13 @@ describe(commands.HIDEDEFAULTTHEMES_SET, () => { auth.service.connected = true; auth.service.spoUrl = 'https://contoso.sharepoint.com'; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/homesite/homesite-remove.spec.ts b/src/m365/spo/commands/homesite/homesite-remove.spec.ts index 9bbde96b6c2..c8052ed9f80 100644 --- a/src/m365/spo/commands/homesite/homesite-remove.spec.ts +++ b/src/m365/spo/commands/homesite/homesite-remove.spec.ts @@ -17,7 +17,7 @@ import command from './homesite-remove.js'; describe(commands.HOMESITE_REMOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,17 +47,18 @@ describe(commands.HOMESITE_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -75,22 +76,17 @@ describe(commands.HOMESITE_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the Home Site when confirm option is not passed', async () => { + it('prompts before removing the Home Site when force option is not passed', async () => { await command.action(logger, { options: { debug: true } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing Home Site when confirm option is not passed and prompt not confirmed', async () => { + it('aborts removing Home Site when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); assert(postSpy.notCalled); @@ -118,8 +114,8 @@ describe(commands.HOMESITE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: {} }); assert(homeSiteRemoveCallIssued); diff --git a/src/m365/spo/commands/homesite/homesite-remove.ts b/src/m365/spo/commands/homesite/homesite-remove.ts index 304b585ecf6..a006c4aa90c 100644 --- a/src/m365/spo/commands/homesite/homesite-remove.ts +++ b/src/m365/spo/commands/homesite/homesite-remove.ts @@ -83,14 +83,9 @@ class SpoHomeSiteRemoveCommand extends SpoCommand { await removeHomeSite(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the Home Site?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the Home Site?` }); - if (result.continue) { + if (result) { await removeHomeSite(); } } diff --git a/src/m365/spo/commands/hubsite/hubsite-connect.spec.ts b/src/m365/spo/commands/hubsite/hubsite-connect.spec.ts index a516119c966..d984b84607c 100644 --- a/src/m365/spo/commands/hubsite/hubsite-connect.spec.ts +++ b/src/m365/spo/commands/hubsite/hubsite-connect.spec.ts @@ -62,6 +62,13 @@ describe(commands.HUBSITE_CONNECT, () => { throw 'Invalid requet URL: ' + opts.url; }); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/hubsite/hubsite-disconnect.spec.ts b/src/m365/spo/commands/hubsite/hubsite-disconnect.spec.ts index 4887e101b7a..688ed474d8a 100644 --- a/src/m365/spo/commands/hubsite/hubsite-disconnect.spec.ts +++ b/src/m365/spo/commands/hubsite/hubsite-disconnect.spec.ts @@ -43,7 +43,7 @@ describe(commands.HUBSITE_DISCONNECT, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; let patchStub: sinon.SinonStub<[options: CliRequestOptions]>; before(() => { @@ -62,6 +62,13 @@ describe(commands.HUBSITE_DISCONNECT, () => { throw 'Invalid requet URL: ' + opts.url; }); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -77,17 +84,18 @@ describe(commands.HUBSITE_DISCONNECT, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -132,11 +140,6 @@ describe(commands.HUBSITE_DISCONNECT, () => { it('prompts before disconnecting the hub site when confirmation argument not passed', async () => { await command.action(logger, { options: { id: id } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -230,8 +233,8 @@ describe(commands.HUBSITE_DISCONNECT, () => { throw 'Invalid request URL: ' + opts.url; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/hubsite/hubsite-disconnect.ts b/src/m365/spo/commands/hubsite/hubsite-disconnect.ts index 24559b156e2..03400480e18 100644 --- a/src/m365/spo/commands/hubsite/hubsite-disconnect.ts +++ b/src/m365/spo/commands/hubsite/hubsite-disconnect.ts @@ -124,14 +124,9 @@ class SpoHubSiteDisconnectCommand extends SpoCommand { await disconnectHubSite(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want disconnect hub site '${args.options.id || args.options.title || args.options.url}' from its parent hub site?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want disconnect hub site '${args.options.id || args.options.title || args.options.url}' from its parent hub site?` }); - if (result.continue) { + if (result) { await disconnectHubSite(); } } diff --git a/src/m365/spo/commands/hubsite/hubsite-get.spec.ts b/src/m365/spo/commands/hubsite/hubsite-get.spec.ts index 5fc367c7c94..fcd8229634d 100644 --- a/src/m365/spo/commands/hubsite/hubsite-get.spec.ts +++ b/src/m365/spo/commands/hubsite/hubsite-get.spec.ts @@ -39,6 +39,13 @@ describe(commands.HUBSITE_GET, () => { auth.service.connected = true; auth.service.spoUrl = 'https://contoso.sharepoint.com'; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/hubsite/hubsite-rights-revoke.spec.ts b/src/m365/spo/commands/hubsite/hubsite-rights-revoke.spec.ts index 8249213a8fe..2191c031b84 100644 --- a/src/m365/spo/commands/hubsite/hubsite-rights-revoke.spec.ts +++ b/src/m365/spo/commands/hubsite/hubsite-rights-revoke.spec.ts @@ -21,7 +21,7 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -54,17 +54,18 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -82,7 +83,7 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { assert.notStrictEqual(command.description, null); }); - it('revokes rights to join the specified hub site without prompting for confirmation when confirm option specified', async () => { + it('revokes rights to join the specified hub site without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1 && opts.data === `https://contoso.sharepoint.com/sites/Salesadmin`) { @@ -102,7 +103,7 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { assert(loggerLogSpy.notCalled); }); - it('revokes rights to join the specified hub site without prompting for confirmation when confirm option specified (debug)', async () => { + it('revokes rights to join the specified hub site without prompting for confirmation when force option specified (debug)', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1 && opts.data === `https://contoso.sharepoint.com/sites/Salesadmin`) { @@ -122,21 +123,16 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { assert(loggerLogToStderrSpy.called); }); - it('prompts before revoking the rights when confirm option not passed', async () => { + it('prompts before revoking the rights when force option not passed', async () => { await command.action(logger, { options: { hubSiteUrl: 'https://contoso.sharepoint.com/sites/Sales', principals: 'admin' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts revoking rights when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { hubSiteUrl: 'https://contoso.sharepoint.com/sites/Sales', principals: 'admin' } }); assert(postSpy.notCalled); }); @@ -149,8 +145,8 @@ describe(commands.HUBSITE_RIGHTS_REVOKE, () => { "IsNull": false } ]))); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { hubSiteUrl: 'https://contoso.sharepoint.com/sites/Sales', principals: 'admin' } }); assert(postStub.called); }); diff --git a/src/m365/spo/commands/hubsite/hubsite-rights-revoke.ts b/src/m365/spo/commands/hubsite/hubsite-rights-revoke.ts index 0f989f4695d..22166f8f661 100644 --- a/src/m365/spo/commands/hubsite/hubsite-rights-revoke.ts +++ b/src/m365/spo/commands/hubsite/hubsite-rights-revoke.ts @@ -104,14 +104,9 @@ class SpoHubSiteRightsRevokeCommand extends SpoCommand { await revokeRights(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to revoke rights to join sites to the hub site ${args.options.hubSiteUrl} from the specified users?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to revoke rights to join sites to the hub site ${args.options.hubSiteUrl} from the specified users?` }); - if (result.continue) { + if (result) { await revokeRights(); } } diff --git a/src/m365/spo/commands/hubsite/hubsite-unregister.spec.ts b/src/m365/spo/commands/hubsite/hubsite-unregister.spec.ts index 4d870b83d82..d5ae9fb6d91 100644 --- a/src/m365/spo/commands/hubsite/hubsite-unregister.spec.ts +++ b/src/m365/spo/commands/hubsite/hubsite-unregister.spec.ts @@ -20,7 +20,7 @@ describe(commands.HUBSITE_UNREGISTER, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -52,17 +52,18 @@ describe(commands.HUBSITE_UNREGISTER, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -99,18 +100,13 @@ describe(commands.HUBSITE_UNREGISTER, () => { it('prompts before unregistering the hub site when confirmation argument not passed', async () => { await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/sales' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts unregistering hub site when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/sales' } }); assert(requests.length === 0); @@ -130,8 +126,8 @@ describe(commands.HUBSITE_UNREGISTER, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, url: 'https://contoso.sharepoint.com/sites/sales' } }); }); diff --git a/src/m365/spo/commands/hubsite/hubsite-unregister.ts b/src/m365/spo/commands/hubsite/hubsite-unregister.ts index b618d3ab51a..b4fa565e50e 100644 --- a/src/m365/spo/commands/hubsite/hubsite-unregister.ts +++ b/src/m365/spo/commands/hubsite/hubsite-unregister.ts @@ -87,14 +87,9 @@ class SpoHubSiteUnregisterCommand extends SpoCommand { await unregisterHubSite(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to unregister the site collection ${args.options.url} as a hub site?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to unregister the site collection ${args.options.url} as a hub site?` }); - if (result.continue) { + if (result) { await unregisterHubSite(); } } diff --git a/src/m365/spo/commands/knowledgehub/knowledgehub-remove.spec.ts b/src/m365/spo/commands/knowledgehub/knowledgehub-remove.spec.ts index 91b0d65fbe4..43748b40e93 100644 --- a/src/m365/spo/commands/knowledgehub/knowledgehub-remove.spec.ts +++ b/src/m365/spo/commands/knowledgehub/knowledgehub-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.KNOWLEDGEHUB_REMOVE, () => { let log: string[]; let logger: Logger; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -65,15 +65,16 @@ describe(commands.KNOWLEDGEHUB_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); }); after(() => { @@ -121,26 +122,21 @@ describe(commands.KNOWLEDGEHUB_REMOVE, () => { it('removes Knowledge Hub settings from tenant when confirmation argument not passed', async () => { await command.action(logger, { options: { debug: true } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing Knowledge Hub settings from tenant when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true } }); assert(requests.length === 0); }); it('removes removing Knowledge Hub settings from tenant when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true } }); }); diff --git a/src/m365/spo/commands/knowledgehub/knowledgehub-remove.ts b/src/m365/spo/commands/knowledgehub/knowledgehub-remove.ts index cfe49e0bd36..91a0af6adfc 100644 --- a/src/m365/spo/commands/knowledgehub/knowledgehub-remove.ts +++ b/src/m365/spo/commands/knowledgehub/knowledgehub-remove.ts @@ -87,14 +87,9 @@ class SpoKnowledgehubRemoveCommand extends SpoCommand { await removeKnowledgehub(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove Knowledge Hub Site from your tenant?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove Knowledge Hub Site from your tenant?` }); - if (result.continue) { + if (result) { await removeKnowledgehub(); } } diff --git a/src/m365/spo/commands/list/list-contenttype-remove.spec.ts b/src/m365/spo/commands/list/list-contenttype-remove.spec.ts index 6d234db4fa7..12c56f14b29 100644 --- a/src/m365/spo/commands/list/list-contenttype-remove.spec.ts +++ b/src/m365/spo/commands/list/list-contenttype-remove.spec.ts @@ -24,7 +24,7 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -50,17 +50,19 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -86,11 +88,6 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { id: contentTypeId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -103,18 +100,13 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { id: contentTypeId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing content type from list when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { listId: listId, @@ -137,8 +129,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -165,10 +157,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -195,8 +185,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -223,8 +213,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -250,10 +240,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -279,8 +267,8 @@ describe(commands.LIST_CONTENTTYPE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-contenttype-remove.ts b/src/m365/spo/commands/list/list-contenttype-remove.ts index 178893bb61f..56eb09cc77c 100644 --- a/src/m365/spo/commands/list/list-contenttype-remove.ts +++ b/src/m365/spo/commands/list/list-contenttype-remove.ts @@ -143,14 +143,9 @@ class SpoListContentTypeRemoveCommand extends SpoCommand { await removeContentTypeFromList(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the content type ${args.options.id} from the list ${args.options.listId ? args.options.listId : args.options.listTitle ? args.options.listTitle : args.options.listUrl} in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the content type ${args.options.id} from the list ${args.options.listId ? args.options.listId : args.options.listTitle ? args.options.listTitle : args.options.listUrl} in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeContentTypeFromList(); } } diff --git a/src/m365/spo/commands/list/list-remove.spec.ts b/src/m365/spo/commands/list/list-remove.spec.ts index e245b3fbde1..11bb23e5506 100644 --- a/src/m365/spo/commands/list/list-remove.spec.ts +++ b/src/m365/spo/commands/list/list-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.LIST_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -45,17 +45,19 @@ describe(commands.LIST_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -75,29 +77,19 @@ describe(commands.LIST_REMOVE, () => { it('prompts before removing list when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing list when confirmation argument not passed (title)', async () => { await command.action(logger, { options: { title: 'My list', webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing list when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); assert(requests.length === 0); }); @@ -117,8 +109,8 @@ describe(commands.LIST_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com' } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/list/list-remove.ts b/src/m365/spo/commands/list/list-remove.ts index a2dbd0cea3a..3bf8949a5ea 100644 --- a/src/m365/spo/commands/list/list-remove.ts +++ b/src/m365/spo/commands/list/list-remove.ts @@ -123,14 +123,9 @@ class SpoListRemoveCommand extends SpoCommand { await removeList(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the list ${args.options.id || args.options.title} from site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the list ${args.options.id || args.options.title} from site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeList(); } } diff --git a/src/m365/spo/commands/list/list-retentionlabel-remove.spec.ts b/src/m365/spo/commands/list/list-retentionlabel-remove.spec.ts index 6923a3d70a6..a378aca220c 100644 --- a/src/m365/spo/commands/list/list-retentionlabel-remove.spec.ts +++ b/src/m365/spo/commands/list/list-retentionlabel-remove.spec.ts @@ -14,11 +14,9 @@ import commands from '../../commands.js'; import command from './list-retentionlabel-remove.js'; describe(commands.LIST_RETENTIONLABEL_REMOVE, () => { - let cli: Cli; let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; const listResponse = { "RootFolder": { "ServerRelativeUrl": "/sites/team1/Shared Documents" @@ -26,13 +24,19 @@ describe(commands.LIST_RETENTIONLABEL_REMOVE, () => { }; before(() => { - cli = Cli.getInstance(); sinon.stub(auth, 'restoreAuth').resolves(); sinon.stub(telemetry, 'trackEvent').returns(); sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -48,19 +52,13 @@ describe(commands.LIST_RETENTIONLABEL_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; - }); - sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, - cli.getSettingWithDefaultValue + Cli.promptForConfirmation ]); }); @@ -77,55 +75,48 @@ describe(commands.LIST_RETENTIONLABEL_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the retentionlabel on the specified list when confirm option not passed (listTitle)', async () => { + it('prompts before removing the retentionlabel on the specified list when force option not passed (listTitle)', async () => { + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team1', listTitle: 'MyLibrary' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); - it('prompts before removing the retentionlabel on the specified list when confirm option not passed (listId)', async () => { + it('prompts before removing the retentionlabel on the specified list when force option not passed (listId)', async () => { + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team1', listId: '0CD891EF-AFCE-4E55-B836-FCE03286CCCF' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); - it('prompts before removing the retentionlabel on the specified list when confirm option not passed (listUrl)', async () => { + it('prompts before removing the retentionlabel on the specified list when force option not passed (listUrl)', async () => { + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team1', listUrl: '/sites/team1/MyLibrary' } }); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('aborts removing list retentionlabel when prompt not confirmed', async () => { + sinon.stub(Cli, 'promptForConfirmation').resolves(false); + const getSpy = sinon.spy(request, 'get'); await command.action(logger, { options: { @@ -282,10 +273,8 @@ describe(commands.LIST_RETENTIONLABEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.doesNotReject(command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-retentionlabel-remove.ts b/src/m365/spo/commands/list/list-retentionlabel-remove.ts index f4aeb58b37c..2bfb9d74d1b 100644 --- a/src/m365/spo/commands/list/list-retentionlabel-remove.ts +++ b/src/m365/spo/commands/list/list-retentionlabel-remove.ts @@ -91,14 +91,9 @@ class SpoListRetentionLabelRemoveCommand extends SpoCommand { await this.removeListRetentionLabel(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retention label from list '${args.options.listId || args.options.listTitle || args.options.listUrl}'?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retention label from list '${args.options.listId || args.options.listTitle || args.options.listUrl}'?` }); - if (result.continue) { + if (result) { await this.removeListRetentionLabel(logger, args); } } diff --git a/src/m365/spo/commands/list/list-roleassignment-remove.spec.ts b/src/m365/spo/commands/list/list-roleassignment-remove.spec.ts index 69b8821b06b..3709775b429 100644 --- a/src/m365/spo/commands/list/list-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/list/list-roleassignment-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -29,6 +29,13 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -45,17 +52,19 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, Cli.executeCommandWithOutput, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -302,11 +311,6 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -321,11 +325,6 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -349,8 +348,8 @@ describe(commands.LIST_ROLEASSIGNMENT_REMOVE, () => { throw new CommandError('Unknown case'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-roleassignment-remove.ts b/src/m365/spo/commands/list/list-roleassignment-remove.ts index 0e8489fc8cb..77e5c0ac168 100644 --- a/src/m365/spo/commands/list/list-roleassignment-remove.ts +++ b/src/m365/spo/commands/list/list-roleassignment-remove.ts @@ -155,14 +155,9 @@ class SpoListRoleAssignmentRemoveCommand extends SpoCommand { await removeRoleAssignment(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove role assignment from list ${args.options.listId || args.options.listTitle} from site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove role assignment from list ${args.options.listId || args.options.listTitle} from site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeRoleAssignment(); } } diff --git a/src/m365/spo/commands/list/list-roleinheritance-break.spec.ts b/src/m365/spo/commands/list/list-roleinheritance-break.spec.ts index 617c1753f35..3dbb2b4973d 100644 --- a/src/m365/spo/commands/list/list-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/list/list-roleinheritance-break.spec.ts @@ -18,7 +18,7 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -43,17 +43,19 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -240,8 +242,8 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { }); it('aborts breaking role inheritance when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); const postSpy = sinon.spy(request, 'post'); await command.action(logger, { @@ -262,11 +264,6 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { listTitle: 'test' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -278,11 +275,6 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { listId: '202b8199-b9de-43fd-9737-7f213f51c991' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -295,8 +287,8 @@ describe(commands.LIST_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-roleinheritance-break.ts b/src/m365/spo/commands/list/list-roleinheritance-break.ts index 29b81fa2ea3..cb49d30c6d9 100644 --- a/src/m365/spo/commands/list/list-roleinheritance-break.ts +++ b/src/m365/spo/commands/list/list-roleinheritance-break.ts @@ -140,14 +140,9 @@ class SpoListRoleInheritanceBreakCommand extends SpoCommand { await breakListRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to break the role inheritance of ${args.options.listId ?? args.options.listTitle}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to break the role inheritance of ${args.options.listId ?? args.options.listTitle}?` }); - if (result.continue) { + if (result) { await breakListRoleInheritance(); } } diff --git a/src/m365/spo/commands/list/list-roleinheritance-reset.spec.ts b/src/m365/spo/commands/list/list-roleinheritance-reset.spec.ts index 79c86d85dd0..7513ec938af 100644 --- a/src/m365/spo/commands/list/list-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/list/list-roleinheritance-reset.spec.ts @@ -18,7 +18,7 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -43,17 +43,19 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -190,8 +192,8 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { it('aborts resetting role inheritance when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, @@ -210,11 +212,6 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { listTitle: 'test' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -227,11 +224,6 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -244,8 +236,8 @@ describe(commands.LIST_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-roleinheritance-reset.ts b/src/m365/spo/commands/list/list-roleinheritance-reset.ts index 7c77017f38e..fb60bdbb238 100644 --- a/src/m365/spo/commands/list/list-roleinheritance-reset.ts +++ b/src/m365/spo/commands/list/list-roleinheritance-reset.ts @@ -130,14 +130,9 @@ class SpoListRoleInheritanceResetCommand extends SpoCommand { await resetListRoleInheritance(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to reset the role inheritance of ${args.options.listId ?? args.options.listTitle}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to reset the role inheritance of ${args.options.listId ?? args.options.listTitle}?` }); - if (result.continue) { + if (result) { await resetListRoleInheritance(); } } diff --git a/src/m365/spo/commands/list/list-sensitivitylabel-ensure.spec.ts b/src/m365/spo/commands/list/list-sensitivitylabel-ensure.spec.ts index cdd6f49a427..862b0021290 100644 --- a/src/m365/spo/commands/list/list-sensitivitylabel-ensure.spec.ts +++ b/src/m365/spo/commands/list/list-sensitivitylabel-ensure.spec.ts @@ -46,6 +46,13 @@ describe(commands.LIST_SENSITIVITYLABEL_ENSURE, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/list/list-view-field-remove.spec.ts b/src/m365/spo/commands/list/list-view-field-remove.spec.ts index 6a5ec05cb56..cd74e6c89b2 100644 --- a/src/m365/spo/commands/list/list-view-field-remove.spec.ts +++ b/src/m365/spo/commands/list/list-view-field-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; const stubAllGetRequests: any = () => { return sinon.stub(request, 'get').callsFake(async (opts) => { @@ -103,17 +103,19 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -168,20 +170,13 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { it('prompts before removing field from list view when confirmation argument not passed (list title, view id, field title)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', title: 'Created By' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing field by title from list view when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', title: 'Created By' } }); assert(requests.length === 0); }); @@ -203,10 +198,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', title: 'Created By' } }); let correctRequestIssued = false; requests.forEach(r => { @@ -265,8 +258,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: '0cd891ef-afce-4e55-b836-fce03286cccf', viewTitle: 'MyView', title: 'Created By' } }); let correctRequestIssued = false; @@ -297,8 +290,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: '0cd891ef-afce-4e55-b836-fce03286cccf', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', title: 'Created By' } }); let correctRequestIssued = false; @@ -329,8 +322,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { verbose: true, webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', id: '330f29c5-5c4c-465f-9f4b-7903020ae1ce' } }); let correctRequestIssued = false; @@ -361,8 +354,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', viewTitle: 'MyView', id: '330f29c5-5c4c-465f-9f4b-7903020ae1ce' } }); let correctRequestIssued = false; @@ -393,8 +386,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: '0cd891ef-afce-4e55-b836-fce03286cccf', viewTitle: 'MyView', id: '330f29c5-5c4c-465f-9f4b-7903020ae1ce' } }); let correctRequestIssued = false; @@ -425,8 +418,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: '0cd891ef-afce-4e55-b836-fce03286cccf', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', id: '330f29c5-5c4c-465f-9f4b-7903020ae1ce' } }); let correctRequestIssued = false; @@ -457,8 +450,8 @@ describe(commands.LIST_VIEW_FIELD_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listUrl: '/sites/ninja/Shared Documents', viewId: 'cc27a922-8224-4296-90a5-ebbc54da2e81', id: '330f29c5-5c4c-465f-9f4b-7903020ae1ce' } }); let correctRequestIssued = false; diff --git a/src/m365/spo/commands/list/list-view-field-remove.ts b/src/m365/spo/commands/list/list-view-field-remove.ts index 63f5756b375..e50cb448724 100644 --- a/src/m365/spo/commands/list/list-view-field-remove.ts +++ b/src/m365/spo/commands/list/list-view-field-remove.ts @@ -175,14 +175,9 @@ class SpoListViewFieldRemoveCommand extends SpoCommand { await removeFieldFromView(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the field ${args.options.id || args.options.title} from the view ${args.options.viewId || args.options.viewTitle} from list ${args.options.listId || args.options.listTitle} in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the field ${args.options.id || args.options.title} from the view ${args.options.viewId || args.options.viewTitle} from list ${args.options.listId || args.options.listTitle} in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeFieldFromView(); } } diff --git a/src/m365/spo/commands/list/list-view-remove.spec.ts b/src/m365/spo/commands/list/list-view-remove.spec.ts index e80f31c4672..4a2a81cd5b8 100644 --- a/src/m365/spo/commands/list/list-view-remove.spec.ts +++ b/src/m365/spo/commands/list/list-view-remove.spec.ts @@ -26,7 +26,6 @@ describe(commands.LIST_VIEW_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -50,16 +49,13 @@ describe(commands.LIST_VIEW_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -96,7 +92,10 @@ describe(commands.LIST_VIEW_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified view from list by id and listTitle when confirm option not passed', async () => { + it('prompts before removing the specified view from list by id and listTitle when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: webUrl, @@ -105,16 +104,13 @@ describe(commands.LIST_VIEW_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - - assert(promptIssued); + assert(confirmationStub.calledOnce); }); - it('prompts before removing the specified view from list by title and listId when confirm option not passed', async () => { + it('prompts before removing the specified view from list by title and listId when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: webUrl, @@ -123,16 +119,13 @@ describe(commands.LIST_VIEW_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - - assert(promptIssued); + assert(confirmationStub.calledOnce); }); - it('prompts before removing the specified view from list by title and listUrl when confirm option not passed', async () => { + it('prompts before removing the specified view from list by title and listUrl when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); + await command.action(logger, { options: { webUrl: webUrl, @@ -141,13 +134,7 @@ describe(commands.LIST_VIEW_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('aborts removing view from list when prompt not confirmed', async () => { @@ -174,10 +161,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -198,8 +183,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -221,8 +206,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -244,8 +229,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -266,8 +251,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -289,8 +274,8 @@ describe(commands.LIST_VIEW_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/list/list-view-remove.ts b/src/m365/spo/commands/list/list-view-remove.ts index 128f2e5d6bc..e39af2c24fb 100644 --- a/src/m365/spo/commands/list/list-view-remove.ts +++ b/src/m365/spo/commands/list/list-view-remove.ts @@ -156,14 +156,9 @@ class SpoListViewRemoveCommand extends SpoCommand { await removeViewFromList(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the view ${args.options.id || args.options.title} from the list ${args.options.listId || args.options.listTitle || args.options.listUrl} in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the view ${args.options.id || args.options.title} from the list ${args.options.listId || args.options.listTitle || args.options.listUrl} in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeViewFromList(); } } diff --git a/src/m365/spo/commands/list/list-webhook-remove.spec.ts b/src/m365/spo/commands/list/list-webhook-remove.spec.ts index e74c711f30e..7c275d7551e 100644 --- a/src/m365/spo/commands/list/list-webhook-remove.spec.ts +++ b/src/m365/spo/commands/list/list-webhook-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -46,17 +46,19 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -76,42 +78,25 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { it('prompts before removing webhook from list when confirmation argument not passed (list title)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing webhook from list when confirmation argument not passed (list url)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listUrl: '/sites/ninja/Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing list when confirmation argument not passed (list id)', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: '0cd891ef-afce-4e55-b836-fce03286cccf', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing list when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); assert(requests.length === 0); }); @@ -131,8 +116,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; @@ -161,8 +146,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listTitle: 'Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; @@ -191,8 +176,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: 'dfddade1-4729-428d-881e-7fedf3cae50d', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; @@ -221,8 +206,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/ninja', listId: 'dfddade1-4729-428d-881e-7fedf3cae50d', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; @@ -305,8 +290,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/ninja', listUrl: '/sites/ninja/lists/Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; @@ -335,8 +320,8 @@ describe(commands.LIST_WEBHOOK_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com/sites/ninja', listUrl: '/sites/ninja/lists/Documents', id: 'cc27a922-8224-4296-90a5-ebbc54da2e81' } }); let correctRequestIssued = false; diff --git a/src/m365/spo/commands/list/list-webhook-remove.ts b/src/m365/spo/commands/list/list-webhook-remove.ts index 4565493ad85..639b66c514c 100644 --- a/src/m365/spo/commands/list/list-webhook-remove.ts +++ b/src/m365/spo/commands/list/list-webhook-remove.ts @@ -143,14 +143,9 @@ class SpoListWebhookRemoveCommand extends SpoCommand { await removeWebhook(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove webhook ${args.options.id} from list ${args.options.listTitle || args.options.listId || args.options.listUrl} located at site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove webhook ${args.options.id} from list ${args.options.listTitle || args.options.listId || args.options.listUrl} located at site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeWebhook(); } } diff --git a/src/m365/spo/commands/listitem/listitem-remove.spec.ts b/src/m365/spo/commands/listitem/listitem-remove.spec.ts index e0473f5eba1..01874178f89 100644 --- a/src/m365/spo/commands/listitem/listitem-remove.spec.ts +++ b/src/m365/spo/commands/listitem/listitem-remove.spec.ts @@ -25,7 +25,7 @@ describe(commands.LISTITEM_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -51,17 +51,19 @@ describe(commands.LISTITEM_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -81,31 +83,19 @@ describe(commands.LISTITEM_REMOVE, () => { it('prompts before removing list item when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { id: 1, webUrl: 'https://contoso.sharepoint.com', listTitle: 'Documents' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before removing list item when confirmation argument not passed (title)', async () => { await command.action(logger, { options: { listTitle: 'My list', webUrl: 'https://contoso.sharepoint.com', id: 1 } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing list item when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { listTitle: 'My list', webUrl: 'https://contoso.sharepoint.com', id: 1 } }); assert(requests.length === 0); }); @@ -125,10 +115,8 @@ describe(commands.LISTITEM_REMOVE, () => { return Promise.reject('Invalid request'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { listId: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com', id: 1 } }); let correctRequestIssued = false; requests.forEach(r => { @@ -154,10 +142,8 @@ describe(commands.LISTITEM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { verbose: true, listUrl: listUrl, webUrl: webUrl, id: 1 } }); let correctRequestIssued = false; requests.forEach(r => { @@ -186,10 +172,8 @@ describe(commands.LISTITEM_REMOVE, () => { return Promise.reject('Invalid request'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { listId: 'b2307a39-e878-458b-bc90-03bc578531d6', webUrl: 'https://contoso.sharepoint.com', id: 1, recycle: true } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/listitem/listitem-remove.ts b/src/m365/spo/commands/listitem/listitem-remove.ts index 6274e503d78..200b8c66001 100644 --- a/src/m365/spo/commands/listitem/listitem-remove.ts +++ b/src/m365/spo/commands/listitem/listitem-remove.ts @@ -154,14 +154,9 @@ class SpoListItemRemoveCommand extends SpoCommand { await removeListItem(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to ${args.options.recycle ? "recycle" : "remove"} the list item ${args.options.id} from list ${args.options.listId || args.options.listTitle || args.options.listUrl} located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to ${args.options.recycle ? "recycle" : "remove"} the list item ${args.options.id} from list ${args.options.listId || args.options.listTitle || args.options.listUrl} located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await removeListItem(); } } diff --git a/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.spec.ts b/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.spec.ts index 2a35a644506..52b04e66493 100644 --- a/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.spec.ts +++ b/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.spec.ts @@ -25,7 +25,7 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { let logger: Logger; let loggerLogToStderrSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { cli = Cli.getInstance(); @@ -51,17 +51,19 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { } }; loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -81,20 +83,13 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { it('prompts before removing retentionlabel when confirmation argument not passed (id)', async () => { await command.action(logger, { options: { listItemId: 1, webUrl: webUrl, listTitle: listTitle } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing list item when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { listTitle: listTitle, @@ -106,10 +101,8 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { }); it('removes the retentionlabel based on listId when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/lists(guid'${formatting.encodeQueryParameter(listId)}')/items(1)/SetComplianceTag()`) { @@ -130,10 +123,8 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { }); it('removes the retentionlabel based on listTitle when prompt confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/lists/getByTitle('${formatting.encodeQueryParameter(listTitle)}')/items(1)/SetComplianceTag()`) { @@ -174,10 +165,8 @@ describe(commands.LISTITEM_RETENTIONLABEL_REMOVE, () => { }); it('removes the retentionlabel based on listUrl when prompt confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/GetList(@a1)/items(@a2)/SetComplianceTag()?@a1='%2F${formatting.encodeQueryParameter(listUrl)}'&@a2='1'`) { diff --git a/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.ts b/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.ts index 9d6581728e2..abd12d79551 100644 --- a/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.ts +++ b/src/m365/spo/commands/listitem/listitem-retentionlabel-remove.ts @@ -105,14 +105,9 @@ class SpoListItemRetentionLabelRemoveCommand extends SpoCommand { await this.removeListItemRetentionLabel(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the retentionlabel from list item ${args.options.listItemId} from list '${args.options.listId || args.options.listTitle || args.options.listUrl}' located in site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the retentionlabel from list item ${args.options.listItemId} from list '${args.options.listId || args.options.listTitle || args.options.listUrl}' located in site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeListItemRetentionLabel(logger, args); } } diff --git a/src/m365/spo/commands/listitem/listitem-roleassignment-remove.spec.ts b/src/m365/spo/commands/listitem/listitem-roleassignment-remove.spec.ts index 51498532bef..ebd34335e45 100644 --- a/src/m365/spo/commands/listitem/listitem-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/listitem/listitem-roleassignment-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.LISTITEM_ROLEASSIGNMENT_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -45,17 +45,19 @@ describe(commands.LISTITEM_ROLEASSIGNMENT_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, Cli.executeCommandWithOutput, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -321,11 +323,6 @@ describe(commands.LISTITEM_ROLEASSIGNMENT_REMOVE, () => { groupName: 'someGroup' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -339,11 +336,6 @@ describe(commands.LISTITEM_ROLEASSIGNMENT_REMOVE, () => { groupName: 'someGroup' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -367,10 +359,8 @@ describe(commands.LISTITEM_ROLEASSIGNMENT_REMOVE, () => { throw new CommandError('Unknown case'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/spo/commands/listitem/listitem-roleassignment-remove.ts b/src/m365/spo/commands/listitem/listitem-roleassignment-remove.ts index 8981cce343f..d3f902bf257 100644 --- a/src/m365/spo/commands/listitem/listitem-roleassignment-remove.ts +++ b/src/m365/spo/commands/listitem/listitem-roleassignment-remove.ts @@ -128,14 +128,9 @@ class SpoListItemRoleAssignmentRemoveCommand extends SpoCommand { await this.removeRoleAssignment(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove role assignment from listitem ${args.options.listItemId} from list ${args.options.listId || args.options.listTitle} from site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove role assignment from listitem ${args.options.listItemId} from list ${args.options.listId || args.options.listTitle} from site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeRoleAssignment(logger, args.options); } } diff --git a/src/m365/spo/commands/listitem/listitem-roleinheritance-break.spec.ts b/src/m365/spo/commands/listitem/listitem-roleinheritance-break.spec.ts index 32cc6afa71d..42a5a4d5a1b 100644 --- a/src/m365/spo/commands/listitem/listitem-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/listitem/listitem-roleinheritance-break.spec.ts @@ -19,7 +19,7 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,16 +43,18 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -238,10 +240,8 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { it('aborts breaking role inheritance when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, @@ -263,11 +263,6 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -282,11 +277,6 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -324,10 +314,8 @@ describe(commands.LISTITEM_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/spo/commands/listitem/listitem-roleinheritance-break.ts b/src/m365/spo/commands/listitem/listitem-roleinheritance-break.ts index 28061555ef7..9fe3031f34a 100644 --- a/src/m365/spo/commands/listitem/listitem-roleinheritance-break.ts +++ b/src/m365/spo/commands/listitem/listitem-roleinheritance-break.ts @@ -112,14 +112,9 @@ class SpoListItemRoleInheritanceBreakCommand extends SpoCommand { await this.breakListItemRoleInheritance(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to break the role inheritance of ${args.options.listItemId} in list ${args.options.listId ?? args.options.listTitle}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to break the role inheritance of ${args.options.listItemId} in list ${args.options.listId ?? args.options.listTitle}?` }); - if (result.continue) { + if (result) { await this.breakListItemRoleInheritance(args.options); } } diff --git a/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.spec.ts b/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.spec.ts index fb5a06431ac..53fc784bd8f 100644 --- a/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.spec.ts @@ -19,7 +19,7 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,16 +43,18 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -222,10 +224,8 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { it('aborts resetting role inheritance when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, @@ -247,11 +247,6 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -266,11 +261,6 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -284,10 +274,8 @@ describe(commands.LISTITEM_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, diff --git a/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.ts b/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.ts index 842777a4ca8..e7f6327d803 100644 --- a/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.ts +++ b/src/m365/spo/commands/listitem/listitem-roleinheritance-reset.ts @@ -107,14 +107,9 @@ class SpoListItemRoleInheritanceResetCommand extends SpoCommand { await this.resetListItemRoleInheritance(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to reset the role inheritance of ${args.options.listItemId} in list ${args.options.listId ?? args.options.listTitle}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to reset the role inheritance of ${args.options.listItemId} in list ${args.options.listId ?? args.options.listTitle}?` }); - if (result.continue) { + if (result) { await this.resetListItemRoleInheritance(args.options); } } diff --git a/src/m365/spo/commands/navigation/navigation-node-remove.spec.ts b/src/m365/spo/commands/navigation/navigation-node-remove.spec.ts index d7e795e43cf..753d4b0aa96 100644 --- a/src/m365/spo/commands/navigation/navigation-node-remove.spec.ts +++ b/src/m365/spo/commands/navigation/navigation-node-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.NAVIGATION_NODE_REMOVE, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -52,18 +52,19 @@ describe(commands.NAVIGATION_NODE_REMOVE, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -108,11 +109,6 @@ describe(commands.NAVIGATION_NODE_REMOVE, () => { it('prompts before removing navigation node when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team-a', location: 'TopNavigationBar', id: '2003' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -121,10 +117,8 @@ describe(commands.NAVIGATION_NODE_REMOVE, () => { sinon.stub(request, 'delete').callsFake(() => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team-a', location: 'TopNavigationBar', id: '2003' } }); }); @@ -137,10 +131,8 @@ describe(commands.NAVIGATION_NODE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com/sites/team-a', location: 'TopNavigationBar', id: '2003' } }); assert(loggerLogSpy.notCalled); }); diff --git a/src/m365/spo/commands/navigation/navigation-node-remove.ts b/src/m365/spo/commands/navigation/navigation-node-remove.ts index 348382a4bfd..3d2a6b7e91a 100644 --- a/src/m365/spo/commands/navigation/navigation-node-remove.ts +++ b/src/m365/spo/commands/navigation/navigation-node-remove.ts @@ -90,14 +90,9 @@ class SpoNavigationNodeRemoveCommand extends SpoCommand { await this.removeNode(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the node ${args.options.id} from the navigation?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the node ${args.options.id} from the navigation?` }); - if (result.continue) { + if (result) { await this.removeNode(logger, args.options); } } diff --git a/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.spec.ts b/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.spec.ts index 5c8673ecf51..60c29276426 100644 --- a/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.spec.ts +++ b/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.spec.ts @@ -17,7 +17,7 @@ import command from './orgassetslibrary-remove.js'; describe(commands.ORGASSETSLIBRARY_REMOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -47,17 +47,18 @@ describe(commands.ORGASSETSLIBRARY_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -75,24 +76,17 @@ describe(commands.ORGASSETSLIBRARY_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before removing the Org Assets Library when confirm option is not passed', async () => { + it('prompts before removing the Org Assets Library when force option is not passed', async () => { await command.action(logger, { options: { debug: true } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the Org Assets Library when confirm option is not passed and prompt not confirmed', async () => { + it('aborts removing the Org Assets Library when force option is not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); assert(postSpy.notCalled); @@ -120,10 +114,8 @@ describe(commands.ORGASSETSLIBRARY_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { libraryUrl: '/sites/branding/assets' } }); assert(orgAssetLibRemoveCallIssued); }); @@ -176,10 +168,8 @@ describe(commands.ORGASSETSLIBRARY_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { libraryUrl: '/sites/branding/assets', output: 'json' } }); assert(orgAssetLibRemoveCallIssued); }); diff --git a/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.ts b/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.ts index dc4412284d0..3ca519a8b94 100644 --- a/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.ts +++ b/src/m365/spo/commands/orgassetslibrary/orgassetslibrary-remove.ts @@ -47,14 +47,9 @@ class SpoOrgAssetsLibraryRemoveCommand extends SpoCommand { await this.removeLibrary(logger, args.options.libraryUrl); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the library ${args.options.libraryUrl} as a central location for organization assets?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the library ${args.options.libraryUrl} as a central location for organization assets?` }); - if (result.continue) { + if (result) { await this.removeLibrary(logger, args.options.libraryUrl); } } diff --git a/src/m365/spo/commands/orgnewssite/orgnewssite-remove.spec.ts b/src/m365/spo/commands/orgnewssite/orgnewssite-remove.spec.ts index 78f8d5454a4..8a0f296f150 100644 --- a/src/m365/spo/commands/orgnewssite/orgnewssite-remove.spec.ts +++ b/src/m365/spo/commands/orgnewssite/orgnewssite-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.ORGNEWSSITE_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -49,17 +49,18 @@ describe(commands.ORGNEWSSITE_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -111,10 +112,8 @@ describe(commands.ORGNEWSSITE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { verbose: true, @@ -161,11 +160,6 @@ describe(commands.ORGNEWSSITE_REMOVE, () => { it('prompts before removing', async () => { await command.action(logger, { options: { debug: true, verbose: true, force: false, url: 'https://contoso.sharepoint.com/sites/test1' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -174,10 +168,8 @@ describe(commands.ORGNEWSSITE_REMOVE, () => { const postStub = sinon.stub(request, 'post').callsFake(() => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, verbose: true, force: false, url: 'https://contoso.sharepoint.com/sites/test1' } }); assert(postStub.notCalled); }); diff --git a/src/m365/spo/commands/orgnewssite/orgnewssite-remove.ts b/src/m365/spo/commands/orgnewssite/orgnewssite-remove.ts index af3b4870ef4..463579d24af 100644 --- a/src/m365/spo/commands/orgnewssite/orgnewssite-remove.ts +++ b/src/m365/spo/commands/orgnewssite/orgnewssite-remove.ts @@ -65,14 +65,9 @@ class SpoOrgNewsSiteRemoveCommand extends SpoCommand { await this.removeOrgNewsSite(logger, args.options.url); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove ${args.options.url} from the list of organizational news sites?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove ${args.options.url} from the list of organizational news sites?` }); - if (result.continue) { + if (result) { await this.removeOrgNewsSite(logger, args.options.url); } } diff --git a/src/m365/spo/commands/page/page-remove.spec.ts b/src/m365/spo/commands/page/page-remove.spec.ts index c9b7fc5b459..c1207fcb9a2 100644 --- a/src/m365/spo/commands/page/page-remove.spec.ts +++ b/src/m365/spo/commands/page/page-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.PAGE_REMOVE, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; const fakeRestCalls: (pageName?: string) => sinon.SinonStub = (pageName: string = 'page.aspx') => { return sinon.stub(request, 'post').callsFake(async (opts) => { @@ -63,16 +63,18 @@ describe(commands.PAGE_REMOVE, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -139,11 +141,8 @@ describe(commands.PAGE_REMOVE, () => { it('removes a modern page with confirm prompt', async () => { fakeRestCalls(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: true }; - }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -156,11 +155,8 @@ describe(commands.PAGE_REMOVE, () => { it('removes a modern page (debug) with confirm prompt', async () => { fakeRestCalls(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: true }; - }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -182,21 +178,14 @@ describe(commands.PAGE_REMOVE, () => { webUrl: 'https://contoso.sharepoint.com/sites/team-a' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('should abort page removal when prompt not confirmed', async () => { const postCallSpy = fakeRestCalls(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -210,10 +199,8 @@ describe(commands.PAGE_REMOVE, () => { it('automatically appends the .aspx extension', async () => { fakeRestCalls(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -230,10 +217,8 @@ describe(commands.PAGE_REMOVE, () => { throw { error: { 'odata.error': { message: { value: 'An error has occurred' } } } }; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await assert.rejects(command.action(logger, { options: { diff --git a/src/m365/spo/commands/page/page-remove.ts b/src/m365/spo/commands/page/page-remove.ts index 10ab74c6f8c..26bc07cc2cc 100644 --- a/src/m365/spo/commands/page/page-remove.ts +++ b/src/m365/spo/commands/page/page-remove.ts @@ -59,15 +59,9 @@ class SpoPageRemoveCommand extends SpoCommand { await this.removePage(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>( - { - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the page '${args.options.name}'?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the page '${args.options.name}'?` }); + + if (result) { await this.removePage(logger, args); } } diff --git a/src/m365/spo/commands/propertybag/propertybag-remove.spec.ts b/src/m365/spo/commands/propertybag/propertybag-remove.spec.ts index 725d95ea2a7..e8fe48a972f 100644 --- a/src/m365/spo/commands/propertybag/propertybag-remove.spec.ts +++ b/src/m365/spo/commands/propertybag/propertybag-remove.spec.ts @@ -21,7 +21,7 @@ describe(commands.PROPERTYBAG_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; const stubAllPostRequests = ( requestObjectIdentityResp: any = null, folderObjectIdentityResp: any = null, @@ -120,11 +120,12 @@ describe(commands.PROPERTYBAG_REMOVE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); @@ -133,7 +134,7 @@ describe(commands.PROPERTYBAG_REMOVE, () => { request.post, (command as any).removePropertyWithIdentityResp, (command as any).removeProperty, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -173,11 +174,6 @@ describe(commands.PROPERTYBAG_REMOVE, () => { key: 'key1' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -185,10 +181,8 @@ describe(commands.PROPERTYBAG_REMOVE, () => { it('should abort property remove when prompt not confirmed', async () => { const postCallsSpy: sinon.SinonStub = stubAllPostRequests(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', @@ -202,10 +196,8 @@ describe(commands.PROPERTYBAG_REMOVE, () => { const postCallsSpy: sinon.SinonStub = stubAllPostRequests(); const removePropertySpy = sinon.spy((command as any), 'removeProperty'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', diff --git a/src/m365/spo/commands/propertybag/propertybag-remove.ts b/src/m365/spo/commands/propertybag/propertybag-remove.ts index 094ffd14ebe..2ef06cd0202 100644 --- a/src/m365/spo/commands/propertybag/propertybag-remove.ts +++ b/src/m365/spo/commands/propertybag/propertybag-remove.ts @@ -74,14 +74,9 @@ class SpoPropertyBagRemoveCommand extends SpoPropertyBagBaseCommand { await this.removeProperty(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the ${args.options.key} property?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the ${args.options.key} property?` }); - if (result.continue) { + if (result) { await this.removeProperty(args); } } diff --git a/src/m365/spo/commands/roledefinition/roledefinition-remove.spec.ts b/src/m365/spo/commands/roledefinition/roledefinition-remove.spec.ts index b5be2e54c64..0587744649b 100644 --- a/src/m365/spo/commands/roledefinition/roledefinition-remove.spec.ts +++ b/src/m365/spo/commands/roledefinition/roledefinition-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.ROLEDEFINITION_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -43,16 +43,18 @@ describe(commands.ROLEDEFINITION_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -111,20 +113,13 @@ describe(commands.ROLEDEFINITION_REMOVE, () => { it('prompts before removing role definition when confirmation argument not passed', async () => { await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: 1 } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing role definition when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { webUrl: 'https://contoso.sharepoint.com', id: 1 } }); assert(requests.length === 0); }); @@ -144,10 +139,8 @@ describe(commands.ROLEDEFINITION_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com', id: 1 } }); let correctRequestIssued = false; requests.forEach(r => { diff --git a/src/m365/spo/commands/roledefinition/roledefinition-remove.ts b/src/m365/spo/commands/roledefinition/roledefinition-remove.ts index af54d639d7c..e01e5aa38e2 100644 --- a/src/m365/spo/commands/roledefinition/roledefinition-remove.ts +++ b/src/m365/spo/commands/roledefinition/roledefinition-remove.ts @@ -73,14 +73,9 @@ class SpoRoleDefinitionRemoveCommand extends SpoCommand { await this.removeRoleDefinition(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the role definition with id ${args.options.id} from site ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the role definition with id ${args.options.id} from site ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeRoleDefinition(logger, args); } } diff --git a/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.spec.ts b/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.spec.ts index 6a641ee5d91..3cbb369d6b5 100644 --- a/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.spec.ts +++ b/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.spec.ts @@ -20,7 +20,7 @@ describe(commands.SERVICEPRINCIPAL_SET, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve()); @@ -52,17 +52,18 @@ describe(commands.SERVICEPRINCIPAL_SET, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -189,32 +190,20 @@ describe(commands.SERVICEPRINCIPAL_SET, () => { it('prompts before enabling service principal when confirmation argument not passed', async () => { await command.action(logger, { options: { enabled: true } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('prompts before disabling service principal when confirmation argument not passed', async () => { await command.action(logger, { options: { enabled: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts enabling service principal when prompt not confirmed', async () => { const requestPostSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { enabled: true } }); assert(requestPostSpy.notCalled); }); @@ -232,10 +221,8 @@ describe(commands.SERVICEPRINCIPAL_SET, () => { } ])); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { enabled: true } }); assert(loggerLogSpy.calledWith({ AccountEnabled: true, diff --git a/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.ts b/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.ts index 67e3ec75ead..d2ffaa35160 100644 --- a/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.ts +++ b/src/m365/spo/commands/serviceprincipal/serviceprincipal-set.ts @@ -66,14 +66,9 @@ class SpoServicePrincipalSetCommand extends SpoCommand { await this.toggleServicePrincipal(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to ${args.options.enabled ? 'enable' : 'disable'} the service principal?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to ${args.options.enabled ? 'enable' : 'disable'} the service principal?` }); - if (result.continue) { + if (result) { await this.toggleServicePrincipal(logger, args); } } diff --git a/src/m365/spo/commands/site/site-apppermission-remove.spec.ts b/src/m365/spo/commands/site/site-apppermission-remove.spec.ts index 19beb294f18..ff6141d1036 100644 --- a/src/m365/spo/commands/site/site-apppermission-remove.spec.ts +++ b/src/m365/spo/commands/site/site-apppermission-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; let deleteRequestStub: sinon.SinonStub; @@ -82,12 +82,12 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + promptIssued = false; deleteRequestStub = sinon.stub(request, 'delete').callsFake(async (opts) => { if ((opts.url as string).indexOf('/permissions/') > -1) { @@ -104,7 +104,7 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { request.get, request.delete, global.setTimeout, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -205,27 +205,20 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { assert.notStrictEqual(actual, true); }); - it('prompts before removing the site apppermission when confirm option not passed', async () => { + it('prompts before removing the site apppermission when force option not passed', async () => { await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/sitecollection-name', appDisplayName: 'Foo' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts removing the site apppermission when prompt not confirmed', async () => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -237,11 +230,9 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { }); it('removes site apppermission when prompt confirmed (debug)', async () => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); getRequestStub.onCall(0) @@ -271,11 +262,9 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { }); it('removes site apppermission with specified appId', async () => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); getRequestStub.onCall(0) @@ -305,11 +294,9 @@ describe(commands.SITE_APPPERMISSION_REMOVE, () => { }); it('removes site apppermission with specified appDisplayName', async () => { - sinonUtil.restore(Cli.prompt); + sinonUtil.restore(Cli.promptForConfirmation); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); const getRequestStub = sinon.stub(request, 'get'); getRequestStub.onCall(0) diff --git a/src/m365/spo/commands/site/site-apppermission-remove.ts b/src/m365/spo/commands/site/site-apppermission-remove.ts index 41b557c15d0..e8e496b1113 100644 --- a/src/m365/spo/commands/site/site-apppermission-remove.ts +++ b/src/m365/spo/commands/site/site-apppermission-remove.ts @@ -144,14 +144,9 @@ class SpoSiteAppPermissionRemoveCommand extends GraphCommand { await this.removeSiteAppPermission(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the specified application permission from site ${args.options.siteUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the specified application permission from site ${args.options.siteUrl}?` }); - if (result.continue) { + if (result) { await this.removeSiteAppPermission(logger, args.options); } } diff --git a/src/m365/spo/commands/site/site-commsite-enable.spec.ts b/src/m365/spo/commands/site/site-commsite-enable.spec.ts index 7ee33cc46e4..398b205bb76 100644 --- a/src/m365/spo/commands/site/site-commsite-enable.spec.ts +++ b/src/m365/spo/commands/site/site-commsite-enable.spec.ts @@ -25,6 +25,13 @@ describe(commands.SITE_COMMSITE_ENABLE, () => { sinon.stub(session, 'getId').resolves(); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/site/site-hubsite-disconnect.spec.ts b/src/m365/spo/commands/site/site-hubsite-disconnect.spec.ts index a37c5708f9d..93246bc3caa 100644 --- a/src/m365/spo/commands/site/site-hubsite-disconnect.spec.ts +++ b/src/m365/spo/commands/site/site-hubsite-disconnect.spec.ts @@ -20,7 +20,7 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; let loggerLogToStderrSpy: sinon.SinonSpy; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -52,17 +52,18 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { }; loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -79,7 +80,7 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { assert.notStrictEqual(command.description, null); }); - it('disconnects the site from its hub site without prompting for confirmation when confirm option specified', async () => { + it('disconnects the site from its hub site without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/sites/Sales/_api/site/JoinHubSite('00000000-0000-0000-0000-000000000000')`) { return { @@ -94,7 +95,7 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { assert(loggerLogSpy.notCalled); }); - it('disconnects the site from its hub site without prompting for confirmation when confirm option specified (debug)', async () => { + it('disconnects the site from its hub site without prompting for confirmation when force option specified (debug)', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/sites/Sales/_api/site/JoinHubSite('00000000-0000-0000-0000-000000000000')`) { return { @@ -109,23 +110,16 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { assert(loggerLogToStderrSpy.called); }); - it('prompts before disconnecting the specified site from its hub site when confirm option not passed', async () => { + it('prompts before disconnecting the specified site from its hub site when force option not passed', async () => { await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/Sales' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); it('aborts disconnecting site from its hub site when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/Sales' } }); assert(postSpy.notCalled); }); @@ -136,10 +130,8 @@ describe(commands.SITE_HUBSITE_DISCONNECT, () => { "odata.null": true }); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/Sales' } }); assert(postStub.called); }); diff --git a/src/m365/spo/commands/site/site-hubsite-disconnect.ts b/src/m365/spo/commands/site/site-hubsite-disconnect.ts index 0e6cf356d4a..b9f6f7132fe 100644 --- a/src/m365/spo/commands/site/site-hubsite-disconnect.ts +++ b/src/m365/spo/commands/site/site-hubsite-disconnect.ts @@ -63,14 +63,9 @@ class SpoSiteHubSiteDisconnectCommand extends SpoCommand { await this.disconnectHubSite(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to disconnect the site collection ${args.options.siteUrl} from its hub site?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to disconnect the site collection ${args.options.siteUrl} from its hub site?` }); - if (result.continue) { + if (result) { await this.disconnectHubSite(logger, args); } } diff --git a/src/m365/spo/commands/site/site-recyclebinitem-clear.spec.ts b/src/m365/spo/commands/site/site-recyclebinitem-clear.spec.ts index 89658d5a914..f3ac0ab9ff4 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-clear.spec.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-clear.spec.ts @@ -17,7 +17,7 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -42,17 +42,18 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -79,22 +80,17 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { assert(actual); }); - it('prompts before removing the items from the recycle bin when confirm option not passed', async () => { + it('prompts before removing the items from the recycle bin when force option not passed', async () => { await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the items from the recycle bin when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the items from the recycle bin when force option not passed and prompt not confirmed', async () => { const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/RecycleBin/DeleteAll`) { return { @@ -114,7 +110,7 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { assert(postStub.notCalled); }); - it('removes all items from the first-stage recycle bin with confirm option', async () => { + it('removes all items from the first-stage recycle bin with force option', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/RecycleBin/DeleteAll`) { return { @@ -145,10 +141,8 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -159,7 +153,7 @@ describe(commands.SITE_RECYCLEBINITEM_CLEAR, () => { assert(postStub.called); }); - it('removes all items from the second-stage recycle bin with confirm option', async () => { + it('removes all items from the second-stage recycle bin with force option', async () => { const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/site/RecycleBin/DeleteAllSecondStageItems`) { return { diff --git a/src/m365/spo/commands/site/site-recyclebinitem-clear.ts b/src/m365/spo/commands/site/site-recyclebinitem-clear.ts index 0c8c6546713..65ba01fbfa4 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-clear.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-clear.ts @@ -74,14 +74,9 @@ class SpoSiteRecycleBinItemClearCommand extends SpoCommand { await this.clearRecycleBin(args, logger); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to clear the recycle bin of site ${args.options.siteUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to clear the recycle bin of site ${args.options.siteUrl}?` }); - if (result.continue) { + if (result) { await this.clearRecycleBin(args, logger); } } diff --git a/src/m365/spo/commands/site/site-recyclebinitem-move.spec.ts b/src/m365/spo/commands/site/site-recyclebinitem-move.spec.ts index cf2c8e50a3f..e738f3e5880 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-move.spec.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-move.spec.ts @@ -17,7 +17,7 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -42,17 +42,18 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -89,23 +90,18 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { assert(actual); }); - it('prompts before moving the items to the second-stage recycle bin when confirm option not passed', async () => { + it('prompts before moving the items to the second-stage recycle bin when force option not passed', async () => { await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com', all: true } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts moving the items to the second-stage recycle bin when confirm option not passed and prompt not confirmed', async () => { + it('aborts moving the items to the second-stage recycle bin when force option not passed and prompt not confirmed', async () => { const postStub = sinon.stub(request, 'post').resolves(); await command.action(logger, { options: { @@ -117,7 +113,7 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { assert(postStub.notCalled); }); - it('moves items to the second-stage recycle bin with ids and confirm option', async () => { + it('moves items to the second-stage recycle bin with ids and force option', async () => { const postStub = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === 'https://contoso.sharepoint.com/_api/web/recycleBin/MoveAllToSecondStage') { return { @@ -151,10 +147,8 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -166,7 +160,7 @@ describe(commands.SITE_RECYCLEBINITEM_MOVE, () => { assert(postSpy.called); }); - it('moves all items to the second-stage recycle bin with all and confirm option', async () => { + it('moves all items to the second-stage recycle bin with all and force option', async () => { const postSpy = sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/web/recycleBin/MoveAllToSecondStage`) { return { diff --git a/src/m365/spo/commands/site/site-recyclebinitem-move.ts b/src/m365/spo/commands/site/site-recyclebinitem-move.ts index 5ea63413c3a..632a2cbcff4 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-move.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-move.ts @@ -90,14 +90,9 @@ class SpoSiteRecycleBinItemMoveCommand extends SpoCommand { await this.moveRecycleBinItem(args, logger); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: 'Are you sure you want to move these items to the second-stage recycle bin?' - }); + const result = await Cli.promptForConfirmation({ message: 'Are you sure you want to move these items to the second-stage recycle bin?' }); - if (result.continue) { + if (result) { await this.moveRecycleBinItem(args, logger); } } diff --git a/src/m365/spo/commands/site/site-recyclebinitem-remove.spec.ts b/src/m365/spo/commands/site/site-recyclebinitem-remove.spec.ts index 068eeddf620..b655f874ee4 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-remove.spec.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.SITE_RECYCLEBINITEM_REMOVE, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -42,17 +42,18 @@ describe(commands.SITE_RECYCLEBINITEM_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -84,23 +85,18 @@ describe(commands.SITE_RECYCLEBINITEM_REMOVE, () => { assert(actual); }); - it('prompts before removing the items from the recycle bin when confirm option not passed', async () => { + it('prompts before removing the items from the recycle bin when force option not passed', async () => { await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com', ids: '85528dee-00d5-4c38-a6ba-e2abace32f63,aecb840f-20e9-4ff8-accf-5df8eaad31a1' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the items from the recycle bin when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the items from the recycle bin when force option not passed and prompt not confirmed', async () => { const postStub = sinon.stub(request, 'post').resolves(); await command.action(logger, { options: { @@ -112,7 +108,7 @@ describe(commands.SITE_RECYCLEBINITEM_REMOVE, () => { assert(postStub.notCalled); }); - it('removes items from the recycle bin with ids and confirm option', async () => { + it('removes items from the recycle bin with ids and force option', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://contoso.sharepoint.com/_api/site/RecycleBin/DeleteByIds`) { return { @@ -144,10 +140,8 @@ describe(commands.SITE_RECYCLEBINITEM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/site/site-recyclebinitem-remove.ts b/src/m365/spo/commands/site/site-recyclebinitem-remove.ts index e8174d909f7..9baa0b6afc0 100644 --- a/src/m365/spo/commands/site/site-recyclebinitem-remove.ts +++ b/src/m365/spo/commands/site/site-recyclebinitem-remove.ts @@ -77,14 +77,9 @@ class SpoSiteRecycleBinItemRemoveCommand extends SpoCommand { await this.removeRecycleBinItem(args, logger); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to permanently delete ${args.options.ids.split(',').length} item(s) from the site recycle bin?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to permanently delete ${args.options.ids.split(',').length} item(s) from the site recycle bin?` }); - if (result.continue) { + if (result) { await this.removeRecycleBinItem(args, logger); } } diff --git a/src/m365/spo/commands/site/site-remove.spec.ts b/src/m365/spo/commands/site/site-remove.spec.ts index 5a0395efc65..27643cb79ba 100644 --- a/src/m365/spo/commands/site/site-remove.spec.ts +++ b/src/m365/spo/commands/site/site-remove.spec.ts @@ -52,9 +52,7 @@ describe(commands.SITE_REMOVE, () => { loggerLogSpy = sinon.spy(logger, 'log'); loggerLogToStderrSpy = sinon.spy(logger, 'logToStderr'); requests = []; - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); }); afterEach(() => { @@ -65,7 +63,7 @@ describe(commands.SITE_REMOVE, () => { request.delete, global.setTimeout, spo.ensureFormDigest, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -142,10 +140,8 @@ describe(commands.SITE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/demosite', debug: true, verbose: true } }); assert(loggerLogToStderrSpy.called); }); @@ -982,10 +978,8 @@ describe(commands.SITE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/sites/demositeGrouped', debug: true, verbose: true, skipRecycleBin: true } }); }); @@ -1080,10 +1074,8 @@ describe(commands.SITE_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); sinon.stub(global, 'setTimeout').callsFake((fn) => { fn(); diff --git a/src/m365/spo/commands/site/site-remove.ts b/src/m365/spo/commands/site/site-remove.ts index 254e4930b1f..cf9f02fd586 100644 --- a/src/m365/spo/commands/site/site-remove.ts +++ b/src/m365/spo/commands/site/site-remove.ts @@ -85,14 +85,9 @@ class SpoSiteRemoveCommand extends SpoCommand { await this.removeSite(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the site ${args.options.url}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the site ${args.options.url}?` }); - if (result.continue) { + if (result) { await this.removeSite(logger, args); } } diff --git a/src/m365/spo/commands/sitedesign/sitedesign-remove.spec.ts b/src/m365/spo/commands/sitedesign/sitedesign-remove.spec.ts index 2ef2c0e84f7..86345be1520 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-remove.spec.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-remove.spec.ts @@ -19,7 +19,6 @@ describe(commands.SITEDESIGN_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; before(() => { sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve()); @@ -51,16 +50,13 @@ describe(commands.SITEDESIGN_REMOVE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -78,7 +74,7 @@ describe(commands.SITEDESIGN_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('removes the specified site design without prompting for confirmation when confirm option specified', async () => { + it('removes the specified site design without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake((opts) => { if ((opts.url as string).indexOf(`/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteDesign`) > -1 && JSON.stringify(opts.data) === JSON.stringify({ @@ -96,15 +92,13 @@ describe(commands.SITEDESIGN_REMOVE, () => { assert(loggerLogSpy.notCalled); }); - it('prompts before removing the specified site design when confirm option not passed', async () => { - await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); - let promptIssued = false; + it('prompts before removing the specified site design when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('aborts removing site design when prompt not confirmed', async () => { @@ -117,10 +111,8 @@ describe(commands.SITEDESIGN_REMOVE, () => { it('removes the app when prompt confirmed', async () => { const postStub = sinon.stub(request, 'post').callsFake(() => Promise.resolve()); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); assert(postStub.called); diff --git a/src/m365/spo/commands/sitedesign/sitedesign-remove.ts b/src/m365/spo/commands/sitedesign/sitedesign-remove.ts index 341be7b3fe9..d61e406a3d3 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-remove.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-remove.ts @@ -91,14 +91,9 @@ class SpoSiteDesignRemoveCommand extends SpoCommand { await removeSiteDesign(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the site design ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the site design ${args.options.id}?` }); - if (result.continue) { + if (result) { await removeSiteDesign(); } } diff --git a/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.spec.ts b/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.spec.ts index 3c6ff10eacc..aa909ede2b3 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.spec.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.spec.ts @@ -19,7 +19,7 @@ describe(commands.SITEDESIGN_RIGHTS_REVOKE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').callsFake(() => Promise.resolve()); @@ -51,17 +51,18 @@ describe(commands.SITEDESIGN_RIGHTS_REVOKE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -79,7 +80,7 @@ describe(commands.SITEDESIGN_RIGHTS_REVOKE, () => { assert.notStrictEqual(command.description, null); }); - it('revokes access to the specified site design from the specified principal without prompting for confirmation when confirm option specified', async () => { + it('revokes access to the specified site design from the specified principal without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake((opts) => { if ((opts.url as string).indexOf(`/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.RevokeSiteDesignRights`) > -1 && JSON.stringify(opts.data) === JSON.stringify({ @@ -155,13 +156,8 @@ describe(commands.SITEDESIGN_RIGHTS_REVOKE, () => { assert(loggerLogSpy.notCalled); }); - it('prompts before revoking access to the specified site design when confirm option not passed', async () => { + it('prompts before revoking access to the specified site design when force option not passed', async () => { await command.action(logger, { options: { siteDesignId: 'b2307a39-e878-458b-bc90-03bc578531d6', principals: 'PattiF' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -174,10 +170,8 @@ describe(commands.SITEDESIGN_RIGHTS_REVOKE, () => { it('revokes site design access when prompt confirmed', async () => { const postStub = sinon.stub(request, 'post').callsFake(() => Promise.resolve()); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { siteDesignId: 'b2307a39-e878-458b-bc90-03bc578531d6', principals: 'PattiF' } }); assert(postStub.called); diff --git a/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.ts b/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.ts index 21c7913cceb..ccc27ff35b2 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-rights-revoke.ts @@ -98,14 +98,9 @@ class SpoSiteDesignRightsRevokeCommand extends SpoCommand { await revokePermissions(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to revoke access to site design ${args.options.siteDesignId} from the specified users?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to revoke access to site design ${args.options.siteDesignId} from the specified users?` }); - if (result.continue) { + if (result) { await revokePermissions(); } } diff --git a/src/m365/spo/commands/sitedesign/sitedesign-task-remove.spec.ts b/src/m365/spo/commands/sitedesign/sitedesign-task-remove.spec.ts index 08304bedf08..d079d47cd86 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-task-remove.spec.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-task-remove.spec.ts @@ -19,7 +19,6 @@ describe(commands.SITEDESIGN_TASK_REMOVE, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; - let promptOptions: any; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -51,16 +50,13 @@ describe(commands.SITEDESIGN_TASK_REMOVE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -77,7 +73,7 @@ describe(commands.SITEDESIGN_TASK_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('removes the specified site design task without prompting for confirmation when confirm option specified', async () => { + it('removes the specified site design task without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf(`/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.RemoveSiteDesignTask`) > -1 && JSON.stringify(opts.data) === JSON.stringify({ @@ -95,15 +91,13 @@ describe(commands.SITEDESIGN_TASK_REMOVE, () => { assert(loggerLogSpy.notCalled); }); - it('prompts before removing the specified site design task when confirm option not passed', async () => { - await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); - let promptIssued = false; + it('prompts before removing the specified site design task when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('aborts removing site design task when prompt not confirmed', async () => { @@ -116,10 +110,8 @@ describe(commands.SITEDESIGN_TASK_REMOVE, () => { it('removes the site design task when prompt confirmed', async () => { const postStub = sinon.stub(request, 'post').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); assert(postStub.called); }); diff --git a/src/m365/spo/commands/sitedesign/sitedesign-task-remove.ts b/src/m365/spo/commands/sitedesign/sitedesign-task-remove.ts index 6cd3922f15b..e645e6cc3ec 100644 --- a/src/m365/spo/commands/sitedesign/sitedesign-task-remove.ts +++ b/src/m365/spo/commands/sitedesign/sitedesign-task-remove.ts @@ -69,14 +69,9 @@ class SpoSiteDesignTaskRemoveCommand extends SpoCommand { await this.removeSiteDesignTask(logger, args.options.id); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the site design task ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the site design task ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeSiteDesignTask(logger, args.options.id); } } diff --git a/src/m365/spo/commands/sitescript/sitescript-remove.spec.ts b/src/m365/spo/commands/sitescript/sitescript-remove.spec.ts index 80fef1b8aff..7b1eb017b48 100644 --- a/src/m365/spo/commands/sitescript/sitescript-remove.spec.ts +++ b/src/m365/spo/commands/sitescript/sitescript-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.SITESCRIPT_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -49,17 +49,18 @@ describe(commands.SITESCRIPT_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -77,7 +78,7 @@ describe(commands.SITESCRIPT_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('removes the specified site script without prompting for confirmation when confirm option specified', async () => { + it('removes the specified site script without prompting for confirmation when force option specified', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf(`/_api/Microsoft.Sharepoint.Utilities.WebTemplateExtensions.SiteScriptUtility.DeleteSiteScript`) > -1 && JSON.stringify(opts.data) === JSON.stringify({ @@ -94,13 +95,8 @@ describe(commands.SITESCRIPT_REMOVE, () => { await command.action(logger, { options: { force: true, id: '0f27a016-d277-4bb4-b3c3-b5b040c9559b' } }); }); - it('prompts before removing the specified site script when confirm option not passed', async () => { + it('prompts before removing the specified site script when force option not passed', async () => { await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -114,10 +110,8 @@ describe(commands.SITESCRIPT_REMOVE, () => { it('removes the app when prompt confirmed', async () => { const postStub = sinon.stub(request, 'post').resolves(); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { id: 'b2307a39-e878-458b-bc90-03bc578531d6' } }); assert(postStub.called); }); diff --git a/src/m365/spo/commands/sitescript/sitescript-remove.ts b/src/m365/spo/commands/sitescript/sitescript-remove.ts index 042b8e5c99c..7061ee1a583 100644 --- a/src/m365/spo/commands/sitescript/sitescript-remove.ts +++ b/src/m365/spo/commands/sitescript/sitescript-remove.ts @@ -69,14 +69,9 @@ class SpoSiteScriptRemoveCommand extends SpoCommand { await this.removeSiteScript(logger, args.options.id); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the site script ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the site script ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeSiteScript(logger, args.options.id); } } diff --git a/src/m365/spo/commands/storageentity/storageentity-remove.spec.ts b/src/m365/spo/commands/storageentity/storageentity-remove.spec.ts index 0cf4dcbc11d..825d18eb3d8 100644 --- a/src/m365/spo/commands/storageentity/storageentity-remove.spec.ts +++ b/src/m365/spo/commands/storageentity/storageentity-remove.spec.ts @@ -19,7 +19,7 @@ describe(commands.STORAGEENTITY_REMOVE, () => { let cli: Cli; let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -52,17 +52,19 @@ describe(commands.STORAGEENTITY_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -98,11 +100,6 @@ describe(commands.STORAGEENTITY_REMOVE, () => { it('prompts before removing tenant property when confirmation argument not passed', async () => { await command.action(logger, { options: { debug: true, key: 'existingproperty', appCatalogUrl: 'https://contoso.sharepoint.com/sites/appcatalog' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -121,10 +118,8 @@ describe(commands.STORAGEENTITY_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, key: 'existingproperty', appCatalogUrl: 'https://contoso.sharepoint.com/sites/appcatalog' } }); assert.strictEqual(postStub.lastCall.args[0].url, 'https://contoso-admin.sharepoint.com/_vti_bin/client.svc/ProcessQuery'); @@ -147,10 +142,8 @@ describe(commands.STORAGEENTITY_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { debug: true, key: 'nonexistentproperty', appCatalogUrl: 'https://contoso.sharepoint.com/sites/appcatalog' } } as any), new CommandError('File Not Found.')); assert.strictEqual(postStub.lastCall.args[0].url, 'https://contoso-admin.sharepoint.com/_vti_bin/client.svc/ProcessQuery'); @@ -216,10 +209,8 @@ describe(commands.STORAGEENTITY_REMOVE, () => { sinonUtil.restore(spo.getRequestDigest); sinon.stub(spo, 'getRequestDigest').rejects(new Error('getRequestDigest error')); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { debug: true, key: 'nonexistentproperty', appCatalogUrl: 'https://contoso.sharepoint.com/sites/appcatalog' } } as any), new CommandError('getRequestDigest error')); }); diff --git a/src/m365/spo/commands/storageentity/storageentity-remove.ts b/src/m365/spo/commands/storageentity/storageentity-remove.ts index 21040e419a1..267701aa8b2 100644 --- a/src/m365/spo/commands/storageentity/storageentity-remove.ts +++ b/src/m365/spo/commands/storageentity/storageentity-remove.ts @@ -69,14 +69,9 @@ class SpoStorageEntityRemoveCommand extends SpoCommand { await this.removeTenantProperty(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to delete the ${args.options.key} tenant property?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to delete the ${args.options.key} tenant property?` }); - if (result.continue) { + if (result) { await this.removeTenantProperty(logger, args); } } diff --git a/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.spec.ts b/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.spec.ts index 2d9edfef860..c8479cf0887 100644 --- a/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.spec.ts +++ b/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.spec.ts @@ -51,7 +51,7 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -61,6 +61,13 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { auth.service.connected = true; auth.service.spoUrl = spoUrl; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -76,18 +83,19 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -180,27 +188,20 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified tenant applicationcustomizer when confirm option not passed', async () => { + it('prompts before removing the specified tenant applicationcustomizer when force option not passed', async () => { await command.action(logger, { options: { id: id } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified tenant applicationcustomizer when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified tenant applicationcustomizer when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: id @@ -268,10 +269,8 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -303,10 +302,8 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -338,10 +335,8 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -373,10 +368,8 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -443,10 +436,8 @@ describe(commands.TENANT_APPLICATIONCUSTOMIZER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.ts b/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.ts index 4b77a95361e..5bef07a24ac 100644 --- a/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.ts +++ b/src/m365/spo/commands/tenant/tenant-applicationcustomizer-remove.ts @@ -98,14 +98,9 @@ class SpoTenantApplicationCustomizerRemoveCommand extends SpoCommand { return await this.removeTenantApplicationCustomizer(logger, args); } - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the tenant applicationcustomizer ${args.options.id || args.options.title || args.options.clientSideComponentId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the tenant applicationcustomizer ${args.options.id || args.options.title || args.options.clientSideComponentId}?` }); - if (result.continue) { + if (result) { await this.removeTenantApplicationCustomizer(logger, args); } } diff --git a/src/m365/spo/commands/tenant/tenant-commandset-get.spec.ts b/src/m365/spo/commands/tenant/tenant-commandset-get.spec.ts index b009978090a..3c096ba99ae 100644 --- a/src/m365/spo/commands/tenant/tenant-commandset-get.spec.ts +++ b/src/m365/spo/commands/tenant/tenant-commandset-get.spec.ts @@ -60,6 +60,13 @@ describe(commands.TENANT_COMMANDSET_GET, () => { auth.service.connected = true; auth.service.spoUrl = spoUrl; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/spo/commands/tenant/tenant-commandset-remove.spec.ts b/src/m365/spo/commands/tenant/tenant-commandset-remove.spec.ts index 464e6cfe7b0..277a2a169d2 100644 --- a/src/m365/spo/commands/tenant/tenant-commandset-remove.spec.ts +++ b/src/m365/spo/commands/tenant/tenant-commandset-remove.spec.ts @@ -50,7 +50,7 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -60,6 +60,13 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { auth.service.connected = true; auth.service.spoUrl = spoUrl; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -75,18 +82,20 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.post, - Cli.prompt, + Cli.promptForConfirmation, Cli.handleMultipleResultsFound ]); }); @@ -179,27 +188,20 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { assert.strictEqual(actual, true); }); - it('prompts before removing the specified tenant command set when confirm option not passed', async () => { + it('prompts before removing the specified tenant command set when force option not passed', async () => { await command.action(logger, { options: { id: id } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified tenant command set when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified tenant command set when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'post'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: id @@ -267,10 +269,8 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -302,10 +302,8 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -337,10 +335,8 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -372,10 +368,8 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -469,10 +463,8 @@ describe(commands.TENANT_COMMANDSET_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/tenant/tenant-commandset-remove.ts b/src/m365/spo/commands/tenant/tenant-commandset-remove.ts index 8c8a18ea3d2..b5fa7e44f11 100644 --- a/src/m365/spo/commands/tenant/tenant-commandset-remove.ts +++ b/src/m365/spo/commands/tenant/tenant-commandset-remove.ts @@ -98,14 +98,9 @@ class SpoTenantCommandSetRemoveCommand extends SpoCommand { return await this.removeTenantCommandSet(logger, args); } - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the tenant commandset ${args.options.id || args.options.title || args.options.clientSideComponentId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the tenant commandset ${args.options.id || args.options.title || args.options.clientSideComponentId}?` }); - if (result.continue) { + if (result) { await this.removeTenantCommandSet(logger, args); } } diff --git a/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.spec.ts b/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.spec.ts index 9f31900abd7..7317cae0718 100644 --- a/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.spec.ts +++ b/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.spec.ts @@ -49,16 +49,14 @@ describe(commands.TENANT_RECYCLEBINITEM_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); }); afterEach(() => { sinonUtil.restore([ request.post, global.setTimeout, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -112,10 +110,8 @@ describe(commands.TENANT_RECYCLEBINITEM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { siteUrl: 'https://contoso.sharepoint.com/sites/hr' } }); sinonUtil.restore([ request.post diff --git a/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.ts b/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.ts index 153dfdae9be..e6bfebcbecf 100644 --- a/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.ts +++ b/src/m365/spo/commands/tenant/tenant-recyclebinitem-remove.ts @@ -72,14 +72,9 @@ class SpoTenantRecycleBinItemRemoveCommand extends SpoCommand { await this.removeDeletedSite(logger, args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the deleted site collection ${args.options.siteUrl} from tenant recycle bin?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the deleted site collection ${args.options.siteUrl} from tenant recycle bin?` }); - if (result.continue) { + if (result) { await this.removeDeletedSite(logger, args); } } diff --git a/src/m365/spo/commands/theme/theme-remove.spec.ts b/src/m365/spo/commands/theme/theme-remove.spec.ts index 850329d043e..81648fa2d7a 100644 --- a/src/m365/spo/commands/theme/theme-remove.spec.ts +++ b/src/m365/spo/commands/theme/theme-remove.spec.ts @@ -15,7 +15,7 @@ import command from './theme-remove.js'; describe(commands.THEME_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let loggerLogSpy: sinon.SinonSpy; before(() => { @@ -41,17 +41,18 @@ describe(commands.THEME_REMOVE, () => { } }; loggerLogSpy = sinon.spy(logger, 'log'); - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -71,11 +72,6 @@ describe(commands.THEME_REMOVE, () => { it('should prompt before removing theme when confirmation argument not passed', async () => { await command.action(logger, { options: { name: 'Contoso' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -134,10 +130,8 @@ describe(commands.THEME_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -160,10 +154,8 @@ describe(commands.THEME_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { diff --git a/src/m365/spo/commands/theme/theme-remove.ts b/src/m365/spo/commands/theme/theme-remove.ts index 0c2361e6204..5acf46dd6f7 100644 --- a/src/m365/spo/commands/theme/theme-remove.ts +++ b/src/m365/spo/commands/theme/theme-remove.ts @@ -55,14 +55,9 @@ class SpoThemeRemoveCommand extends SpoCommand { await this.removeTheme(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the theme` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the theme` }); - if (result.continue) { + if (result) { await this.removeTheme(logger, args.options); } } diff --git a/src/m365/spo/commands/user/user-remove.spec.ts b/src/m365/spo/commands/user/user-remove.spec.ts index ba4bee0a1b8..f58e5bc62bd 100644 --- a/src/m365/spo/commands/user/user-remove.spec.ts +++ b/src/m365/spo/commands/user/user-remove.spec.ts @@ -18,7 +18,7 @@ describe(commands.USER_REMOVE, () => { let log: any[]; let requests: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -45,18 +45,19 @@ describe(commands.USER_REMOVE, () => { } }; requests = []; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -113,11 +114,6 @@ describe(commands.USER_REMOVE, () => { id: 10 } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -130,11 +126,6 @@ describe(commands.USER_REMOVE, () => { loginName: "i:0#.f|membership|john.doe@mytenant.onmicrosoft.com" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -200,10 +191,8 @@ describe(commands.USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: "https://contoso.sharepoint.com/subsite", @@ -229,10 +218,8 @@ describe(commands.USER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { webUrl: "https://contoso.sharepoint.com/subsite", diff --git a/src/m365/spo/commands/user/user-remove.ts b/src/m365/spo/commands/user/user-remove.ts index 0992dc5712f..bf437c2ed30 100644 --- a/src/m365/spo/commands/user/user-remove.ts +++ b/src/m365/spo/commands/user/user-remove.ts @@ -80,14 +80,9 @@ class SpoUserRemoveCommand extends SpoCommand { await this.removeUser(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove specified user from the site ${args.options.webUrl}` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove specified user from the site ${args.options.webUrl}` }); - if (result.continue) { + if (result) { await this.removeUser(logger, args.options); } } diff --git a/src/m365/spo/commands/web/web-remove.spec.ts b/src/m365/spo/commands/web/web-remove.spec.ts index 35420f9b591..777e785f552 100644 --- a/src/m365/spo/commands/web/web-remove.spec.ts +++ b/src/m365/spo/commands/web/web-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.WEB_REMOVE, () => { let log: any[]; let requests: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -43,17 +43,18 @@ describe(commands.WEB_REMOVE, () => { } }; requests = []; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: true }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(true); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -99,11 +100,6 @@ describe(commands.WEB_REMOVE, () => { }); await command.action(logger, { options: { url: 'https://contoso.sharepoint.com/subsite' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -145,10 +141,8 @@ describe(commands.WEB_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/web/web-remove.ts b/src/m365/spo/commands/web/web-remove.ts index 98c1b34ef46..b52540bce28 100644 --- a/src/m365/spo/commands/web/web-remove.ts +++ b/src/m365/spo/commands/web/web-remove.ts @@ -62,14 +62,9 @@ class SpoWebRemoveCommand extends SpoCommand { await this.removeWeb(logger, args.options.url); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the subsite ${args.options.url}` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the subsite ${args.options.url}` }); - if (result.continue) { + if (result) { await this.removeWeb(logger, args.options.url); } } diff --git a/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts b/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts index 8d91370c531..2157c19a637 100644 --- a/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts @@ -20,7 +20,7 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { let logger: Logger; let commandInfo: CommandInfo; let requests: any[]; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -45,17 +45,19 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, Cli.executeCommandWithOutput, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -245,11 +247,6 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -272,10 +269,8 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { throw new CommandError('Unknown case'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/web/web-roleassignment-remove.ts b/src/m365/spo/commands/web/web-roleassignment-remove.ts index 0b8177e1611..8d0281088f8 100644 --- a/src/m365/spo/commands/web/web-roleassignment-remove.ts +++ b/src/m365/spo/commands/web/web-roleassignment-remove.ts @@ -98,14 +98,9 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { await this.removeRoleAssignment(logger, args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove role assignment from web ${args.options.webUrl}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove role assignment from web ${args.options.webUrl}?` }); - if (result.continue) { + if (result) { await this.removeRoleAssignment(logger, args.options); } } diff --git a/src/m365/spo/commands/web/web-roleinheritance-break.spec.ts b/src/m365/spo/commands/web/web-roleinheritance-break.spec.ts index 11ba4cab97f..339607eabea 100644 --- a/src/m365/spo/commands/web/web-roleinheritance-break.spec.ts +++ b/src/m365/spo/commands/web/web-roleinheritance-break.spec.ts @@ -16,7 +16,7 @@ import command from './web-roleinheritance-break.js'; describe(commands.WEB_ROLEINHERITANCE_BREAK, () => { let log: any[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -41,16 +41,18 @@ describe(commands.WEB_ROLEINHERITANCE_BREAK, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -91,11 +93,6 @@ describe(commands.WEB_ROLEINHERITANCE_BREAK, () => { }); await command.action(logger, { options: { webUrl: "https://contoso.sharepoint.com/subsite" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -108,10 +105,8 @@ describe(commands.WEB_ROLEINHERITANCE_BREAK, () => { throw 'Invalid request URL: ' + opts.url; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/spo/commands/web/web-roleinheritance-break.ts b/src/m365/spo/commands/web/web-roleinheritance-break.ts index d35ddd29c80..6a300e58d85 100644 --- a/src/m365/spo/commands/web/web-roleinheritance-break.ts +++ b/src/m365/spo/commands/web/web-roleinheritance-break.ts @@ -78,14 +78,9 @@ class SpoWebRoleInheritanceBreakCommand extends SpoCommand { await this.breakRoleInheritance(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to break the role inheritance of subsite ${args.options.webUrl}` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to break the role inheritance of subsite ${args.options.webUrl}` }); - if (result.continue) { + if (result) { await this.breakRoleInheritance(args.options); } } diff --git a/src/m365/spo/commands/web/web-roleinheritance-reset.spec.ts b/src/m365/spo/commands/web/web-roleinheritance-reset.spec.ts index 2eb506db3c7..b6448b0be62 100644 --- a/src/m365/spo/commands/web/web-roleinheritance-reset.spec.ts +++ b/src/m365/spo/commands/web/web-roleinheritance-reset.spec.ts @@ -17,7 +17,7 @@ describe(commands.WEB_ROLEINHERITANCE_RESET, () => { let log: any[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -41,16 +41,18 @@ describe(commands.WEB_ROLEINHERITANCE_RESET, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -133,11 +135,6 @@ describe(commands.WEB_ROLEINHERITANCE_RESET, () => { it('prompts before resetting role inheritance when confirmation argument not passed', async () => { await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -152,10 +149,8 @@ describe(commands.WEB_ROLEINHERITANCE_RESET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => { - return { continue: true }; - }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, webUrl: 'https://contoso.sharepoint.com' } }); assert(resetInheritanceCallIssued); }); diff --git a/src/m365/spo/commands/web/web-roleinheritance-reset.ts b/src/m365/spo/commands/web/web-roleinheritance-reset.ts index 03d81267f6f..9df845b57cd 100644 --- a/src/m365/spo/commands/web/web-roleinheritance-reset.ts +++ b/src/m365/spo/commands/web/web-roleinheritance-reset.ts @@ -68,14 +68,9 @@ class SpoWebRoleInheritanceResetCommand extends SpoCommand { await this.resetWebRoleInheritance(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to reset the role inheritance of ${args.options.webUrl}` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to reset the role inheritance of ${args.options.webUrl}` }); - if (result.continue) { + if (result) { await this.resetWebRoleInheritance(args.options); } } diff --git a/src/m365/teams/commands/app/app-remove.spec.ts b/src/m365/teams/commands/app/app-remove.spec.ts index 9efa38d8f83..ef7f056fc22 100644 --- a/src/m365/teams/commands/app/app-remove.spec.ts +++ b/src/m365/teams/commands/app/app-remove.spec.ts @@ -48,7 +48,7 @@ describe(commands.APP_REMOVE, () => { afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -122,14 +122,14 @@ describe(commands.APP_REMOVE, () => { throw 'Invalid request'; }); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, filePath: 'teamsapp.zip', id: `e3e29acb-8c79-412b-b746-e6c39ff4cd22` } }); assert(removeTeamsAppCalled); }); it('aborts removing Teams app when prompt not confirmed', async () => { - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); command.action(logger, { options: { id: `e3e29acb-8c79-412b-b746-e6c39ff4cd22` } }); assert(requests.length === 0); diff --git a/src/m365/teams/commands/app/app-remove.ts b/src/m365/teams/commands/app/app-remove.ts index 3b2bedfe211..e0821fe4465 100644 --- a/src/m365/teams/commands/app/app-remove.ts +++ b/src/m365/teams/commands/app/app-remove.ts @@ -90,14 +90,9 @@ class TeamsAppRemoveCommand extends GraphCommand { await removeApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the Teams app ${appId} from the app catalog?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the Teams app ${appId} from the app catalog?` }); - if (result.continue) { + if (result) { await removeApp(); } } diff --git a/src/m365/teams/commands/app/app-uninstall.spec.ts b/src/m365/teams/commands/app/app-uninstall.spec.ts index 349d9faf7f1..c926118a659 100644 --- a/src/m365/teams/commands/app/app-uninstall.spec.ts +++ b/src/m365/teams/commands/app/app-uninstall.spec.ts @@ -48,7 +48,7 @@ describe(commands.APP_UNINSTALL, () => { afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -104,7 +104,7 @@ describe(commands.APP_UNINSTALL, () => { throw 'Invalid request'; }); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { teamId: 'c527a470-a882-481c-981c-ee6efaba85c7', @@ -115,7 +115,7 @@ describe(commands.APP_UNINSTALL, () => { }); it('aborts uninstalling an app from a Microsoft Teams team when prompt not confirmed', async () => { - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); command.action(logger, { options: { teamId: 'c527a470-a882-481c-981c-ee6efaba85c7', diff --git a/src/m365/teams/commands/app/app-uninstall.ts b/src/m365/teams/commands/app/app-uninstall.ts index 134442473f3..a09822a3559 100644 --- a/src/m365/teams/commands/app/app-uninstall.ts +++ b/src/m365/teams/commands/app/app-uninstall.ts @@ -92,14 +92,9 @@ class TeamsAppUninstallCommand extends GraphCommand { await uninstallApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to uninstall the app with id ${args.options.id} from the Microsoft Teams team ${args.options.teamId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to uninstall the app with id ${args.options.id} from the Microsoft Teams team ${args.options.teamId}?` }); - if (result.continue) { + if (result) { await uninstallApp(); } } diff --git a/src/m365/teams/commands/cache/cache-remove.spec.ts b/src/m365/teams/commands/cache/cache-remove.spec.ts index 2af2c7919d4..ab6aabc378e 100644 --- a/src/m365/teams/commands/cache/cache-remove.spec.ts +++ b/src/m365/teams/commands/cache/cache-remove.spec.ts @@ -20,7 +20,6 @@ describe(commands.CACHE_REMOVE, () => { 11352`; let log: string[]; let logger: Logger; - let promptOptions: any; let commandInfo: CommandInfo; before(() => { @@ -47,18 +46,13 @@ describe(commands.CACHE_REMOVE, () => { } }; - promptOptions = undefined; - - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: true }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); }); afterEach(() => { sinonUtil.restore([ fs.existsSync, - Cli.prompt, + Cli.promptForConfirmation, (command as any).exec, (process as any).kill ]); @@ -77,25 +71,17 @@ describe(commands.CACHE_REMOVE, () => { assert.notStrictEqual(command.description, null); }); - it('prompts before clear cache when confirm option not passed', async () => { + it('prompts before clear cache when force option not passed', async () => { sinon.stub(process, 'platform').value('win32'); sinon.stub(process, 'env').value({ 'CLIMICROSOFT365_ENV': '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; - }); + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('fails validation if called from docker container.', async () => { @@ -254,8 +240,8 @@ describe(commands.CACHE_REMOVE, () => { sinon.stub(process, 'platform').value('darwin'); sinon.stub(process, 'env').value({ 'CLIMICROSOFT365_ENV': '' }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: {} }); assert(execStub.notCalled); diff --git a/src/m365/teams/commands/cache/cache-remove.ts b/src/m365/teams/commands/cache/cache-remove.ts index 8b8600c73b8..7f41277071e 100644 --- a/src/m365/teams/commands/cache/cache-remove.ts +++ b/src/m365/teams/commands/cache/cache-remove.ts @@ -80,14 +80,9 @@ class TeamsCacheRemoveCommand extends AnonymousCommand { await logger.logToStderr('- Stop the Microsoft Teams client.'); await logger.logToStderr('- Clear the Microsoft Teams cached files.'); - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to clear your Microsoft Teams cache?` - }); - - if (result.continue) { + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to clear your Microsoft Teams cache?` }); + + if (result) { await this.clearTeamsCache(logger); } } diff --git a/src/m365/teams/commands/channel/channel-member-add.spec.ts b/src/m365/teams/commands/channel/channel-member-add.spec.ts index 5fe8677dff8..ea79aab2511 100644 --- a/src/m365/teams/commands/channel/channel-member-add.spec.ts +++ b/src/m365/teams/commands/channel/channel-member-add.spec.ts @@ -190,6 +190,13 @@ describe(commands.CHANNEL_MEMBER_ADD, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { diff --git a/src/m365/teams/commands/channel/channel-member-remove.spec.ts b/src/m365/teams/commands/channel/channel-member-remove.spec.ts index 2d8df9af9a6..e0b0bcbd9f8 100644 --- a/src/m365/teams/commands/channel/channel-member-remove.spec.ts +++ b/src/m365/teams/commands/channel/channel-member-remove.spec.ts @@ -28,7 +28,6 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; let commandInfo: CommandInfo; before(() => { @@ -38,6 +37,13 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { sinon.stub(session, 'getId').returns(''); auth.service.connected = true; commandInfo = Cli.getCommandInfo(command); + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); beforeEach(() => { @@ -54,18 +60,14 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { } }; - promptOptions = undefined; + sinon.stub(Cli, 'promptForConfirmation').resolves(true); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: true }; - }); (command as any).items = []; }); afterEach(() => { sinonUtil.restore([ - Cli.prompt, + Cli.promptForConfirmation, request.get, request.delete, Cli.handleMultipleResultsFound @@ -584,8 +586,8 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { it('aborts user removal when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: false }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -597,12 +599,9 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { assert(postSpy.notCalled); }); - it('prompts before user removal when confirm option not passed', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; - }); + it('prompts before user removal when force option not passed', async () => { + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { @@ -611,13 +610,8 @@ describe(commands.CHANNEL_MEMBER_REMOVE, () => { id: '00000' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('correctly handles error when retrieving all teams', async () => { diff --git a/src/m365/teams/commands/channel/channel-member-remove.ts b/src/m365/teams/commands/channel/channel-member-remove.ts index 2c301ea0bc4..4da61b800ca 100644 --- a/src/m365/teams/commands/channel/channel-member-remove.ts +++ b/src/m365/teams/commands/channel/channel-member-remove.ts @@ -146,14 +146,9 @@ class TeamsChannelMemberRemoveCommand extends GraphCommand { const userName = args.options.userName || args.options.userId || args.options.id; const teamName = args.options.teamName || args.options.teamId; const channelName = args.options.channelName || args.options.channelId; - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the member ${userName} from the channel ${channelName} in team ${teamName}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the member ${userName} from the channel ${channelName} in team ${teamName}?` }); - if (result.continue) { + if (result) { await removeMember(); } } diff --git a/src/m365/teams/commands/channel/channel-remove.spec.ts b/src/m365/teams/commands/channel/channel-remove.spec.ts index 5d0d2c9297b..ca5559c30e2 100644 --- a/src/m365/teams/commands/channel/channel-remove.spec.ts +++ b/src/m365/teams/commands/channel/channel-remove.spec.ts @@ -22,7 +22,7 @@ describe(commands.CHANNEL_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -47,18 +47,19 @@ describe(commands.CHANNEL_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -134,7 +135,7 @@ describe(commands.CHANNEL_REMOVE, () => { }), new CommandError(errorMessage)); }); - it('prompts before removing the specified channel when confirm option not passed (debug)', async () => { + it('prompts before removing the specified channel when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, @@ -143,16 +144,11 @@ describe(commands.CHANNEL_REMOVE, () => { } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified channel when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified channel when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { @@ -194,7 +190,7 @@ describe(commands.CHANNEL_REMOVE, () => { }), new CommandError(errorMessage)); }); - it('removes specified channel when id is passed with confirm option', async () => { + it('removes specified channel when id is passed with force option', async () => { sinon.stub(request, 'delete').returns(Promise.resolve()); await command.action(logger, { @@ -215,10 +211,8 @@ describe(commands.CHANNEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -253,8 +247,8 @@ describe(commands.CHANNEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { @@ -293,8 +287,8 @@ describe(commands.CHANNEL_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/teams/commands/channel/channel-remove.ts b/src/m365/teams/commands/channel/channel-remove.ts index 6e3a5d776bb..6b2a1d07bab 100644 --- a/src/m365/teams/commands/channel/channel-remove.ts +++ b/src/m365/teams/commands/channel/channel-remove.ts @@ -130,14 +130,9 @@ class TeamsChannelRemoveCommand extends GraphCommand { } else { const channel = args.options.name ? args.options.name : args.options.id; - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the channel ${channel} from team ${args.options.teamId || args.options.teamName}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the channel ${channel} from team ${args.options.teamId || args.options.teamName}?` }); - if (result.continue) { + if (result) { await removeChannel(); } } diff --git a/src/m365/teams/commands/chat/chat-member-remove.spec.ts b/src/m365/teams/commands/chat/chat-member-remove.spec.ts index 09c1189397c..c88983be7b8 100644 --- a/src/m365/teams/commands/chat/chat-member-remove.spec.ts +++ b/src/m365/teams/commands/chat/chat-member-remove.spec.ts @@ -43,7 +43,7 @@ describe(commands.CHAT_MEMBER_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; - let promptOptions: any; + let promptIssued: boolean = false; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -67,18 +67,19 @@ describe(commands.CHAT_MEMBER_REMOVE, () => { log.push(msg); } }; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); - promptOptions = undefined; + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ odata.getAllItems, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -145,8 +146,8 @@ describe(commands.CHAT_MEMBER_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { chatId: chatId, userName: userPrincipalName, verbose: true } }); assert(deleteStub.called); @@ -178,19 +179,14 @@ describe(commands.CHAT_MEMBER_REMOVE, () => { new CommandError(`Member with userId '${userId}' could not be found in the chat.`)); }); - it('prompts before removing the specified message when confirm option not passed', async () => { + it('prompts before removing the specified message when force option not passed', async () => { await command.action(logger, { options: { chatId: chatId, id: chatMemberId } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified chat member when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified chat member when force option not passed and prompt not confirmed', async () => { const deleteStub = sinon.stub(request, 'delete').resolves(); await command.action(logger, { options: { chatId: chatId, userId: userId } }); diff --git a/src/m365/teams/commands/chat/chat-member-remove.ts b/src/m365/teams/commands/chat/chat-member-remove.ts index 308d76a1441..c19430e5864 100644 --- a/src/m365/teams/commands/chat/chat-member-remove.ts +++ b/src/m365/teams/commands/chat/chat-member-remove.ts @@ -118,14 +118,9 @@ class TeamsChatMemberRemoveCommand extends GraphCommand { await removeUserFromChat(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove member ${args.options.id || args.options.userId || args.options.userName} from chat with id ${args.options.chatId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove member ${args.options.id || args.options.userId || args.options.userName} from chat with id ${args.options.chatId}?` }); - if (result.continue) { + if (result) { await removeUserFromChat(); } } diff --git a/src/m365/teams/commands/tab/tab-remove.spec.ts b/src/m365/teams/commands/tab/tab-remove.spec.ts index fb2c88e03a7..3d702c2a405 100644 --- a/src/m365/teams/commands/tab/tab-remove.spec.ts +++ b/src/m365/teams/commands/tab/tab-remove.spec.ts @@ -17,7 +17,7 @@ describe(commands.TAB_REMOVE, () => { let cli: Cli; let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -43,18 +43,19 @@ describe(commands.TAB_REMOVE, () => { log.push(msg); } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; sinon.stub(cli, 'getSettingWithDefaultValue').callsFake(((settingName, defaultValue) => defaultValue)); }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -125,7 +126,7 @@ describe(commands.TAB_REMOVE, () => { }); - it('prompts before removing the specified tab when confirm option not passed', async () => { + it('prompts before removing the specified tab when force option not passed', async () => { await command.action(logger, { options: { channelId: '19:f3dcbb1674574677abcae89cb626f1e6@thread.skype', @@ -133,16 +134,11 @@ describe(commands.TAB_REMOVE, () => { id: 'd66b8110-fcad-49e8-8159-0d488ddb7656' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified tab when confirm option not passed (debug)', async () => { + it('prompts before removing the specified tab when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, @@ -151,16 +147,11 @@ describe(commands.TAB_REMOVE, () => { id: 'd66b8110-fcad-49e8-8159-0d488ddb7656' } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified tab when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified tab when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -173,7 +164,7 @@ describe(commands.TAB_REMOVE, () => { assert(postSpy.notCalled); }); - it('aborts removing the specified tab when confirm option not passed and prompt not confirmed (debug)', async () => { + it('aborts removing the specified tab when force option not passed and prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { @@ -195,8 +186,8 @@ describe(commands.TAB_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/teams/commands/tab/tab-remove.ts b/src/m365/teams/commands/tab/tab-remove.ts index a14afaa47cd..52b4b553c5f 100644 --- a/src/m365/teams/commands/tab/tab-remove.ts +++ b/src/m365/teams/commands/tab/tab-remove.ts @@ -101,14 +101,9 @@ class TeamsTabRemoveCommand extends GraphCommand { await removeTab(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the tab with id ${args.options.id} from channel ${args.options.channelId} in team ${args.options.teamId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the tab with id ${args.options.id} from channel ${args.options.channelId} in team ${args.options.teamId}?` }); - if (result.continue) { + if (result) { await removeTab(); } } diff --git a/src/m365/teams/commands/team/team-remove.spec.ts b/src/m365/teams/commands/team/team-remove.spec.ts index bf0e455d94e..2a61330d951 100644 --- a/src/m365/teams/commands/team/team-remove.spec.ts +++ b/src/m365/teams/commands/team/team-remove.spec.ts @@ -16,7 +16,7 @@ import command from './team-remove.js'; describe(commands.TEAM_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -42,18 +42,19 @@ describe(commands.TEAM_REMOVE, () => { } }; - promptOptions = undefined; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.get, request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -113,33 +114,23 @@ describe(commands.TEAM_REMOVE, () => { } as any), new CommandError('The specified team does not exist in the Microsoft Teams')); }); - it('prompts before removing the specified team by id when confirm option not passed', async () => { + it('prompts before removing the specified team by id when force option not passed', async () => { await command.action(logger, { options: { id: "00000000-0000-0000-0000-000000000000" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('prompts before removing the specified team by name when confirm option not passed (debug)', async () => { + it('prompts before removing the specified team by name when force option not passed (debug)', async () => { await command.action(logger, { options: { debug: true, name: "Finance" } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); - it('aborts removing the specified team when confirm option not passed and prompt not confirmed', async () => { + it('aborts removing the specified team when force option not passed and prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { id: "00000000-0000-0000-0000-000000000000" } }); assert(postSpy.notCalled); }); - it('aborts removing the specified team when confirm option not passed and prompt not confirmed (debug)', async () => { + it('aborts removing the specified team when force option not passed and prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); await command.action(logger, { options: { debug: true, id: "00000000-0000-0000-0000-000000000000" } }); assert(postSpy.notCalled); @@ -157,8 +148,8 @@ describe(commands.TEAM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: "00000000-0000-0000-0000-000000000000" } }); assert(teamsDeleteCallIssued); @@ -220,8 +211,8 @@ describe(commands.TEAM_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: { id: '8231f9f2-701f-4c6e-93ce-ecb563e3c1ee' } } as any), new CommandError('No team found with Group Id 8231f9f2-701f-4c6e-93ce-ecb563e3c1ee')); }); diff --git a/src/m365/teams/commands/team/team-remove.ts b/src/m365/teams/commands/team/team-remove.ts index 6c424100136..1bbdc1fbbea 100644 --- a/src/m365/teams/commands/team/team-remove.ts +++ b/src/m365/teams/commands/team/team-remove.ts @@ -115,14 +115,9 @@ class TeamsTeamRemoveCommand extends GraphCommand { await removeTeam(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the team ${args.options.id ? args.options.id : args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the team ${args.options.id ? args.options.id : args.options.name}?` }); - if (result.continue) { + if (result) { await removeTeam(); } } diff --git a/src/m365/teams/commands/user/user-app-remove.spec.ts b/src/m365/teams/commands/user/user-app-remove.spec.ts index d2e479b23d1..cf24f75b3ab 100644 --- a/src/m365/teams/commands/user/user-app-remove.spec.ts +++ b/src/m365/teams/commands/user/user-app-remove.spec.ts @@ -16,7 +16,7 @@ import command from './user-app-remove.js'; describe(commands.USER_APP_REMOVE, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let commandInfo: CommandInfo; before(() => { @@ -42,16 +42,18 @@ describe(commands.USER_APP_REMOVE, () => { } }; (command as any).items = []; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -95,10 +97,7 @@ describe(commands.USER_APP_REMOVE, () => { id: 'YzUyN2E0NzAtYTg4Mi00ODFjLTk4MWMtZWU2ZWZhYmE4NWM3IyM0ZDFlYTA0Ny1mMTk2LTQ1MGQtYjJlOS0wZDI4NTViYTA1YTY=' } } as any); - let promptIssued = false; - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } + assert(promptIssued); }); @@ -140,8 +139,8 @@ describe(commands.USER_APP_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').resolves({ continue: true }); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { diff --git a/src/m365/teams/commands/user/user-app-remove.ts b/src/m365/teams/commands/user/user-app-remove.ts index eb98a07bf51..1cd537aaa84 100644 --- a/src/m365/teams/commands/user/user-app-remove.ts +++ b/src/m365/teams/commands/user/user-app-remove.ts @@ -91,14 +91,9 @@ class TeamsUserAppRemoveCommand extends GraphCommand { await removeApp(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the app with id ${args.options.id} for user ${args.options.userId}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the app with id ${args.options.id} for user ${args.options.userId}?` }); - if (result.continue) { + if (result) { await removeApp(); } } diff --git a/src/m365/todo/commands/list/list-remove.spec.ts b/src/m365/todo/commands/list/list-remove.spec.ts index 2d00f68a7f6..70bb0643fbd 100644 --- a/src/m365/todo/commands/list/list-remove.spec.ts +++ b/src/m365/todo/commands/list/list-remove.spec.ts @@ -17,7 +17,6 @@ describe(commands.LIST_REMOVE, () => { let cli: Cli; let log: string[]; let logger: Logger; - let promptOptions: any; let commandInfo: CommandInfo; before(() => { @@ -27,10 +26,7 @@ describe(commands.LIST_REMOVE, () => { sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); auth.service.connected = true; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: true }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); commandInfo = Cli.getCommandInfo(command); }); @@ -108,7 +104,7 @@ describe(commands.LIST_REMOVE, () => { assert.strictEqual(log.length, 0); }); - it('removes a To Do task list by name when confirm option is passed', async () => { + it('removes a To Do task list by name when force option is passed', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/me/todo/lists?$filter=displayName eq 'FooList'`) { return { @@ -223,7 +219,7 @@ describe(commands.LIST_REMOVE, () => { await assert.rejects(command.action(logger, { options: { name: "FooList" } } as any), new CommandError('An error has occurred')); }); - it('prompts before removing the list when confirm option not passed', async () => { + it('prompts before removing the list when force option not passed', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/me/todo/lists?$filter=displayName eq 'FooList'`) { return { @@ -251,22 +247,15 @@ describe(commands.LIST_REMOVE, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); - command.action(logger, { + await command.action(logger, { options: { name: "FooList" } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('fails validation if both name and id are not set', async () => { diff --git a/src/m365/todo/commands/list/list-remove.ts b/src/m365/todo/commands/list/list-remove.ts index 3f622a27502..d1786156a99 100644 --- a/src/m365/todo/commands/list/list-remove.ts +++ b/src/m365/todo/commands/list/list-remove.ts @@ -65,14 +65,9 @@ class TodoListRemoveCommand extends GraphCommand { await this.removeList(args); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the task list ${args.options.id || args.options.name}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the task list ${args.options.id || args.options.name}?` }); - if (result.continue) { + if (result) { await this.removeList(args); } } diff --git a/src/m365/todo/commands/task/task-remove.spec.ts b/src/m365/todo/commands/task/task-remove.spec.ts index f5f57f99fde..07692e3c18d 100644 --- a/src/m365/todo/commands/task/task-remove.spec.ts +++ b/src/m365/todo/commands/task/task-remove.spec.ts @@ -17,7 +17,6 @@ describe(commands.TASK_REMOVE, () => { let cli: Cli; let log: string[]; let logger: Logger; - let promptOptions: any; let commandInfo: CommandInfo; before(() => { @@ -27,10 +26,7 @@ describe(commands.TASK_REMOVE, () => { sinon.stub(pid, 'getProcessName').callsFake(() => ''); sinon.stub(session, 'getId').callsFake(() => ''); auth.service.connected = true; - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: true }; - }); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); commandInfo = Cli.getCommandInfo(command); }); @@ -109,7 +105,7 @@ describe(commands.TASK_REMOVE, () => { assert.strictEqual(log.length, 0); }); - it('removes a To Do task by task id and task list name when confirm option is passed', async () => { + it('removes a To Do task by task id and task list name when force option is passed', async () => { sinon.stub(request, 'get').callsFake((opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/me/todo/lists?$filter=displayName eq 'Tasks'`) { return Promise.resolve({ @@ -213,7 +209,7 @@ describe(commands.TASK_REMOVE, () => { }); - it('prompts before removing the To Do task when confirm option not passed', async () => { + it('prompts before removing the To Do task when force option not passed', async () => { sinon.stub(request, 'get').callsFake((opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/me/todo/lists?$filter=displayName eq 'Tasks'`) { return Promise.resolve({ @@ -241,24 +237,16 @@ describe(commands.TASK_REMOVE, () => { return Promise.reject('Invalid request'); }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async (options) => { - promptOptions = options; - return { continue: false }; - }); + sinonUtil.restore(Cli.promptForConfirmation); + const confirmationStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { id: "AAMkAGI3NDhlZmQzLWQxYjAtNGJjNy04NmYwLWQ0M2IzZTNlMDUwNAAuAAAAAACQ1l2jfH6VSZraktP8Z7auAQCbV93BagWITZhL3J6BMqhjAAD9pHIhAAA=", listName: "Tasks" } } as any); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } - assert(promptIssued); + assert(confirmationStub.calledOnce); }); it('passes validation when all parameters are valid with listId', async () => { diff --git a/src/m365/todo/commands/task/task-remove.ts b/src/m365/todo/commands/task/task-remove.ts index 9e20cb07ebb..33be545afae 100644 --- a/src/m365/todo/commands/task/task-remove.ts +++ b/src/m365/todo/commands/task/task-remove.ts @@ -110,14 +110,9 @@ class TodoTaskRemoveCommand extends GraphCommand { await removeToDoTask(); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the task ${args.options.id} from list ${args.options.listId || args.options.listName}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the task ${args.options.id} from list ${args.options.listId || args.options.listName}?` }); - if (result.continue) { + if (result) { await removeToDoTask(); } } diff --git a/src/m365/yammer/commands/group/group-user-add.spec.ts b/src/m365/yammer/commands/group/group-user-add.spec.ts index b5d17a2f279..6913a9edf45 100644 --- a/src/m365/yammer/commands/group/group-user-add.spec.ts +++ b/src/m365/yammer/commands/group/group-user-add.spec.ts @@ -45,7 +45,7 @@ describe(commands.GROUP_USER_ADD, () => { afterEach(() => { sinonUtil.restore([ request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -97,9 +97,7 @@ describe(commands.GROUP_USER_ADD, () => { return Promise.reject('Invalid request'); }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, groupId: 1231231 } }); diff --git a/src/m365/yammer/commands/group/group-user-remove.spec.ts b/src/m365/yammer/commands/group/group-user-remove.spec.ts index fa25f6386f0..6af7e2e97ba 100644 --- a/src/m365/yammer/commands/group/group-user-remove.spec.ts +++ b/src/m365/yammer/commands/group/group-user-remove.spec.ts @@ -47,7 +47,7 @@ describe(commands.GROUP_USER_REMOVE, () => { afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -73,9 +73,7 @@ describe(commands.GROUP_USER_REMOVE, () => { }); }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('An error has occurred.')); }); @@ -103,9 +101,7 @@ describe(commands.GROUP_USER_REMOVE, () => { return Promise.reject('Invalid request'); }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, groupId: 1231231 } }); @@ -133,9 +129,7 @@ describe(commands.GROUP_USER_REMOVE, () => { return Promise.reject('Invalid request'); }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, groupId: 1231231, id: 989998789 } }); @@ -143,9 +137,7 @@ describe(commands.GROUP_USER_REMOVE, () => { }); it('prompts before removal when confirmation argument not passed', async () => { - const promptStub: sinon.SinonStub = sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + const promptStub: sinon.SinonStub = sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { groupId: 1231231, id: 989998789 } }); @@ -153,9 +145,7 @@ describe(commands.GROUP_USER_REMOVE, () => { }); it('aborts execution when prompt not confirmed', async () => { - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { groupId: 1231231, id: 989998789 } }); diff --git a/src/m365/yammer/commands/group/group-user-remove.ts b/src/m365/yammer/commands/group/group-user-remove.ts index 903047c00c7..f850b13adac 100644 --- a/src/m365/yammer/commands/group/group-user-remove.ts +++ b/src/m365/yammer/commands/group/group-user-remove.ts @@ -105,14 +105,9 @@ class YammerGroupUserRemoveCommand extends YammerCommand { messagePrompt = `Are you sure you want to remove the user ${args.options.id} from the group ${args.options.groupId}?`; } - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: messagePrompt - }); + const result = await Cli.promptForConfirmation({ message: messagePrompt }); - if (result.continue) { + if (result) { await executeRemoveAction(); } } diff --git a/src/m365/yammer/commands/message/message-like-set.spec.ts b/src/m365/yammer/commands/message/message-like-set.spec.ts index d2ddb954da4..4b83aeefac9 100644 --- a/src/m365/yammer/commands/message/message-like-set.spec.ts +++ b/src/m365/yammer/commands/message/message-like-set.spec.ts @@ -16,7 +16,7 @@ import command from './message-like-set.js'; describe(commands.MESSAGE_LIKE_SET, () => { let log: string[]; let logger: Logger; - let promptOptions: any; + let promptIssued: boolean = false; let requests: any[]; let commandInfo: CommandInfo; @@ -43,17 +43,19 @@ describe(commands.MESSAGE_LIKE_SET, () => { } }; requests = []; - sinon.stub(Cli, 'prompt').callsFake(async (options: any) => { - promptOptions = options; - return { continue: false }; + sinon.stub(Cli, 'promptForConfirmation').callsFake(() => { + promptIssued = true; + return Promise.resolve(false); }); + + promptIssued = false; }); afterEach(() => { sinonUtil.restore([ request.delete, request.post, - Cli.prompt + Cli.promptForConfirmation ]); }); @@ -103,11 +105,6 @@ describe(commands.MESSAGE_LIKE_SET, () => { it('prompts when confirmation argument not passed', async () => { await command.action(logger, { options: { messageId: 1231231, enable: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -163,11 +160,6 @@ describe(commands.MESSAGE_LIKE_SET, () => { it('prompts when disliking and confirmation parameter is denied', async () => { await command.action(logger, { options: { messageId: 1231231, enable: false, force: false } }); - let promptIssued = false; - - if (promptOptions && promptOptions.type === 'confirm') { - promptIssued = true; - } assert(promptIssued); }); @@ -180,20 +172,16 @@ describe(commands.MESSAGE_LIKE_SET, () => { throw 'Invalid request'; }); - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, messageId: 1231231, enable: false } }); assert(requestDeleteStub.called); }); it('Aborts execution when enabled set to false and confirmation is not given', async () => { - sinonUtil.restore(Cli.prompt); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinonUtil.restore(Cli.promptForConfirmation); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { messageId: 1231231, enable: false } }); assert(requests.length === 0); diff --git a/src/m365/yammer/commands/message/message-like-set.ts b/src/m365/yammer/commands/message/message-like-set.ts index f4c238db86d..05a7bd6dad2 100644 --- a/src/m365/yammer/commands/message/message-like-set.ts +++ b/src/m365/yammer/commands/message/message-like-set.ts @@ -79,16 +79,11 @@ class YammerMessageLikeSetCommand extends YammerCommand { await this.executeLikeAction(args.options); } else { - const messagePrompt = `Are you sure you want to unlike message ${args.options.messageId}?`; + const message = `Are you sure you want to unlike message ${args.options.messageId}?`; - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: messagePrompt - }); + const result = await Cli.promptForConfirmation({ message }); - if (result.continue) { + if (result) { await this.executeLikeAction(args.options); } } diff --git a/src/m365/yammer/commands/message/message-remove.spec.ts b/src/m365/yammer/commands/message/message-remove.spec.ts index fd218ed5ecc..32dc56cfc40 100644 --- a/src/m365/yammer/commands/message/message-remove.spec.ts +++ b/src/m365/yammer/commands/message/message-remove.spec.ts @@ -49,7 +49,7 @@ describe(commands.MESSAGE_REMOVE, () => { afterEach(() => { sinonUtil.restore([ request.delete, - Cli.prompt, + Cli.promptForConfirmation, cli.getSettingWithDefaultValue ]); }); @@ -96,9 +96,7 @@ describe(commands.MESSAGE_REMOVE, () => { } throw 'Invalid request'; }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: true } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(true); await command.action(logger, { options: { debug: true, id: 10123190123123, force: false } }); assert.strictEqual(requestDeleteStub.lastCall.args[0].url, 'https://www.yammer.com/api/v1/messages/10123190123123.json'); @@ -112,9 +110,7 @@ describe(commands.MESSAGE_REMOVE, () => { throw 'Invalid request'; }); - sinon.stub(Cli, 'prompt').callsFake(async () => ( - { continue: false } - )); + sinon.stub(Cli, 'promptForConfirmation').resolves(false); await command.action(logger, { options: { debug: true, id: 10123190123123, force: false } }); assert(requestDeleteStub.notCalled); diff --git a/src/m365/yammer/commands/message/message-remove.ts b/src/m365/yammer/commands/message/message-remove.ts index f25a9648647..cca745bdca0 100644 --- a/src/m365/yammer/commands/message/message-remove.ts +++ b/src/m365/yammer/commands/message/message-remove.ts @@ -67,14 +67,9 @@ class YammerMessageRemoveCommand extends YammerCommand { await this.removeMessage(args.options); } else { - const result = await Cli.prompt<{ continue: boolean }>({ - type: 'confirm', - name: 'continue', - default: false, - message: `Are you sure you want to remove the Yammer message ${args.options.id}?` - }); + const result = await Cli.promptForConfirmation({ message: `Are you sure you want to remove the Yammer message ${args.options.id}?` }); - if (result.continue) { + if (result) { await this.removeMessage(args.options); } } diff --git a/src/utils/aadGroup.spec.ts b/src/utils/aadGroup.spec.ts index 35da20998d6..3ab52861f21 100644 --- a/src/utils/aadGroup.spec.ts +++ b/src/utils/aadGroup.spec.ts @@ -32,13 +32,21 @@ describe('utils/aadGroup', () => { log.push(msg); } }; + sinon.stub(Cli.getInstance(), 'getSettingWithDefaultValue').callsFake((settingName: string, defaultValue: any) => { + if (settingName === 'prompt') { + return false; + } + + return defaultValue; + }); }); afterEach(() => { sinonUtil.restore([ request.get, request.patch, - Cli.handleMultipleResultsFound + Cli.handleMultipleResultsFound, + Cli.getInstance().getSettingWithDefaultValue ]); }); diff --git a/src/utils/prompt.ts b/src/utils/prompt.ts index d632647b780..9681d95be80 100644 --- a/src/utils/prompt.ts +++ b/src/utils/prompt.ts @@ -1,13 +1,61 @@ -let inquirer: typeof import('inquirer') | undefined; +import { Separator } from '@inquirer/core'; + +let inquirerInput: typeof import('@inquirer/input') | undefined; +let inquirerConfirm: typeof import('@inquirer/confirm') | undefined; +let inquirerSelect: typeof import('@inquirer/select') | undefined; + +export interface Choice { + name: string; + value: T; + description?: string; +} + +export interface InputConfig { + message: string | Promise | (() => Promise); + default?: string | undefined; + transformer?: ((value: string, { isFinal }: { + isFinal: boolean; + }) => string) | undefined; + validate?: ((value: string) => string | boolean | Promise) | undefined; +} + +export interface ConfirmationConfig { + message: string | Promise | (() => Promise); + default?: boolean | undefined; + transformer?: ((value: boolean) => string) | undefined; +} + +export interface SelectionConfig { + message: string | Promise | (() => Promise); + choices: readonly (Separator | Choice)[]; + pageSize?: number | undefined; +} export const prompt = { /* c8 ignore next 7 */ - async forInput(config: any, answers?: any): Promise { - if (!inquirer) { - inquirer = await import('inquirer'); + async forInput(config: InputConfig): Promise { + if (!inquirerInput) { + inquirerInput = await import('@inquirer/input'); + } + + return inquirerInput.default(config, { output: process.stderr }); + }, + + /* c8 ignore next 7 */ + async forConfirmation(config: ConfirmationConfig): Promise { + if (!inquirerConfirm) { + inquirerConfirm = await import('@inquirer/confirm'); + } + + return inquirerConfirm.default(config, { output: process.stderr }); + }, + + /* c8 ignore next 7 */ + async forSelection(config: SelectionConfig): Promise { + if (!inquirerSelect) { + inquirerSelect = await import('@inquirer/select'); } - const prompt = inquirer.createPromptModule({ output: process.stderr }); - return await prompt(config, answers) as any; + return inquirerSelect.default(config, { output: process.stderr }); } }; \ No newline at end of file