diff --git a/src/m365/entra/commands/groupsetting/groupsetting-add.spec.ts b/src/m365/entra/commands/groupsetting/groupsetting-add.spec.ts index bd43e5a4011..fa8cce47564 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-add.spec.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-add.spec.ts @@ -11,13 +11,14 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsetting-add.js'; +import command, { options } from './groupsetting-add.js'; describe(commands.GROUPSETTING_ADD, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -26,6 +27,7 @@ describe(commands.GROUPSETTING_ADD, () => { sinon.stub(session, 'getId').returns(''); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -145,7 +147,7 @@ describe(commands.GROUPSETTING_ADD, () => { throw 'Invalid Request'; }); - await command.action(logger, { options: { templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' }) }); assert(loggerLogSpy.calledWith({ displayName: null, id: 'cb9ede6b-fa00-474c-b34f-dae81102d210', @@ -234,7 +236,7 @@ describe(commands.GROUPSETTING_ADD, () => { throw 'Invalid Request'; }); - await command.action(logger, { options: { debug: true, templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' }) }); assert(loggerLogSpy.calledWith({ displayName: null, id: 'cb9ede6b-fa00-474c-b34f-dae81102d210', @@ -323,7 +325,7 @@ describe(commands.GROUPSETTING_ADD, () => { throw 'Invalid Request'; }); - await command.action(logger, { options: { templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' }) }); assert(loggerLogSpy.calledWith({ displayName: null, id: 'cb9ede6b-fa00-474c-b34f-dae81102d210', @@ -412,7 +414,7 @@ describe(commands.GROUPSETTING_ADD, () => { throw 'Invalid Request'; }); - await command.action(logger, { options: { debug: true, verbose: true, output: "text", templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, verbose: true, output: "text", templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' }) }); assert.deepEqual(postStub.firstCall.args[0].data, { templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b', values: [ @@ -450,7 +452,7 @@ describe(commands.GROUPSETTING_ADD, () => { } }); - await assert.rejects(command.action(logger, { options: { id: '62375ab9-6b52-47ed-826b-58e47e0e304c' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ templateId: '62375ab9-6b52-47ed-826b-58e47e0e304c' }) } as any), new CommandError(`Resource '62375ab9-6b52-47ed-826b-58e47e0e304c' does not exist or one of its queried reference-property objects are not present.`)); }); @@ -477,18 +479,18 @@ describe(commands.GROUPSETTING_ADD, () => { } }); - await assert.rejects(command.action(logger, { options: { templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ templateId: '62375ab9-6b52-47ed-826b-58e47e0e304b' }) } as any), new CommandError(`A conflicting object with one or more of the specified property values is present in the directory.`)); }); - it('fails validation if the templateId is not a valid GUID', async () => { - const actual = await command.validate({ options: { templateId: 'invalid' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if the templateId is not a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ templateId: 'invalid' }); + assert.strictEqual(actual.success, false); }); - it('passes validation if the templateId is a valid GUID', async () => { - const actual = await command.validate({ options: { templateId: '68be84bf-a585-4776-80b3-30aa5207aa22' } }, commandInfo); - assert.strictEqual(actual, true); + it('passes validation if the templateId is a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ templateId: '68be84bf-a585-4776-80b3-30aa5207aa22' }); + assert.strictEqual(actual.success, true); }); it('allows unknown properties', () => { diff --git a/src/m365/entra/commands/groupsetting/groupsetting-add.ts b/src/m365/entra/commands/groupsetting/groupsetting-add.ts index 325b8439bfb..14baafaba2f 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-add.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-add.ts @@ -1,19 +1,22 @@ import { GroupSettingTemplate } from '@microsoft/microsoft-graph-types'; -import GlobalOptions from '../../../../GlobalOptions.js'; +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; +import { globalOptionsZod } from '../../../../Command.js'; import request, { CliRequestOptions } from '../../../../request.js'; -import { validation } from '../../../../utils/validation.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.looseObject({ + ...globalOptionsZod.shape, + templateId: z.uuid().alias('i') +}); + +declare type Options = z.infer; + interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - templateId: string; -} - class EntraGroupSettingAddCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTING_ADD; @@ -23,37 +26,14 @@ class EntraGroupSettingAddCommand extends GraphCommand { return 'Creates a group setting'; } - constructor() { - super(); - - this.#initOptions(); - this.#initValidators(); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-i, --templateId ' - } - ); - } - - #initValidators(): void { - this.validators.push( - async (args: CommandArgs) => { - if (!validation.isValidGuid(args.options.templateId)) { - return `${args.options.templateId} is not a valid GUID`; - } - - return true; - } - ); - } - public allowUnknownOptions(): boolean | undefined { return true; } + public get schema(): z.ZodType | undefined { + return options; + } + public async commandAction(logger: Logger, args: CommandArgs): Promise { if (this.verbose) { await logger.logToStderr(`Retrieving group setting template with id '${args.options.templateId}'...`); diff --git a/src/m365/entra/commands/groupsetting/groupsetting-get.spec.ts b/src/m365/entra/commands/groupsetting/groupsetting-get.spec.ts index 608a117b00f..896b3e0a1d6 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-get.spec.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-get.spec.ts @@ -11,13 +11,14 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsetting-get.js'; +import command, { options } from './groupsetting-get.js'; describe(commands.GROUPSETTING_GET, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -26,6 +27,7 @@ describe(commands.GROUPSETTING_GET, () => { sinon.stub(session, 'getId').returns(''); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -82,7 +84,7 @@ describe(commands.GROUPSETTING_GET, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' }) }); assert(loggerLogSpy.calledWith({ "displayName": "Group Setting", "id": "1caf7dcd-7e83-4c3a-94f7-932a1299c844", @@ -115,7 +117,7 @@ describe(commands.GROUPSETTING_GET, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { debug: true, id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' }) }); assert(loggerLogSpy.calledWith({ "displayName": "Group Setting", "id": "1caf7dcd-7e83-4c3a-94f7-932a1299c844", @@ -149,28 +151,17 @@ describe(commands.GROUPSETTING_GET, () => { throw 'Invalid request'; }); - await assert.rejects(command.action(logger, { options: { id: '1caf7dcd-7e83-4c3a-94f7-932a1299c843' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ id: '1caf7dcd-7e83-4c3a-94f7-932a1299c843' }) } as any), new CommandError(`Resource '1caf7dcd-7e83-4c3a-94f7-932a1299c843' does not exist or one of its queried reference-property objects are not present.`)); }); - it('fails validation if the id is not a valid GUID', async () => { - const actual = await command.validate({ options: { id: '123' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if the id is not a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: '123' }); + assert.strictEqual(actual.success, false); }); - it('passes validation if the id is a valid GUID', async () => { - const actual = await command.validate({ options: { id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' } }, commandInfo); - assert.strictEqual(actual, true); - }); - - it('supports specifying id', () => { - const options = command.options; - let containsOption = false; - options.forEach(o => { - if (o.option.indexOf('--id') > -1) { - containsOption = true; - } - }); - assert(containsOption); + it('passes validation if the id is a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: '1caf7dcd-7e83-4c3a-94f7-932a1299c844' }); + assert.strictEqual(actual.success, true); }); }); diff --git a/src/m365/entra/commands/groupsetting/groupsetting-get.ts b/src/m365/entra/commands/groupsetting/groupsetting-get.ts index 95305c50ae8..3ae1767de10 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-get.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-get.ts @@ -1,18 +1,21 @@ +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; -import GlobalOptions from '../../../../GlobalOptions.js'; +import { globalOptionsZod } from '../../../../Command.js'; import request, { CliRequestOptions } from '../../../../request.js'; -import { validation } from '../../../../utils/validation.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.strictObject({ + ...globalOptionsZod.shape, + id: z.uuid().alias('i') +}); + +declare type Options = z.infer; + interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - id: string; -} - class EntraGroupSettingGetCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTING_GET; @@ -22,31 +25,8 @@ class EntraGroupSettingGetCommand extends GraphCommand { return 'Gets information about the particular group setting'; } - constructor() { - super(); - - this.#initOptions(); - this.#initValidators(); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-i, --id ' - } - ); - } - - #initValidators(): void { - this.validators.push( - async (args: CommandArgs) => { - if (!validation.isValidGuid(args.options.id)) { - return `${args.options.id} is not a valid GUID`; - } - - return true; - } - ); + public get schema(): z.ZodType | undefined { + return options; } public async commandAction(logger: Logger, args: CommandArgs): Promise { diff --git a/src/m365/entra/commands/groupsetting/groupsetting-list.spec.ts b/src/m365/entra/commands/groupsetting/groupsetting-list.spec.ts index 40482fc5ede..956932e9ae9 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-list.spec.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-list.spec.ts @@ -1,6 +1,8 @@ import assert from 'assert'; import sinon from 'sinon'; import auth from '../../../../Auth.js'; +import { cli } from '../../../../cli/cli.js'; +import { CommandInfo } from '../../../../cli/CommandInfo.js'; import { Logger } from '../../../../cli/Logger.js'; import { CommandError } from '../../../../Command.js'; import request from '../../../../request.js'; @@ -9,12 +11,14 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsetting-list.js'; +import command, { options } from './groupsetting-list.js'; describe(commands.GROUPSETTING_LIST, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; + let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -22,6 +26,8 @@ describe(commands.GROUPSETTING_LIST, () => { sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); auth.connection.active = true; + commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -64,6 +70,16 @@ describe(commands.GROUPSETTING_LIST, () => { assert.deepStrictEqual(command.defaultProperties(), ['id', 'displayName']); }); + it('passes validation with no options', () => { + const actual = commandOptionsSchema.safeParse({}); + assert.strictEqual(actual.success, true); + }); + + it('fails validation with unknown options', () => { + const actual = commandOptionsSchema.safeParse({ unknownOption: 'value' }); + assert.strictEqual(actual.success, false); + }); + it('lists group setting templates', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/groupSettings`) { diff --git a/src/m365/entra/commands/groupsetting/groupsetting-list.ts b/src/m365/entra/commands/groupsetting/groupsetting-list.ts index eeab4ae3ebd..ae75ad7b8e3 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-list.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-list.ts @@ -1,9 +1,13 @@ import { GroupSetting } from '@microsoft/microsoft-graph-types'; +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; +import { globalOptionsZod } from '../../../../Command.js'; import { odata } from '../../../../utils/odata.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.strictObject({ ...globalOptionsZod.shape }); + class EntraGroupSettingListCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTING_LIST; @@ -17,6 +21,10 @@ class EntraGroupSettingListCommand extends GraphCommand { return ['id', 'displayName']; } + public get schema(): z.ZodType | undefined { + return options; + } + public async commandAction(logger: Logger): Promise { try { const groupSettings = await odata.getAllItems(`${this.resource}/v1.0/groupSettings`); diff --git a/src/m365/entra/commands/groupsetting/groupsetting-remove.spec.ts b/src/m365/entra/commands/groupsetting/groupsetting-remove.spec.ts index 3babce302a0..356fb3c207d 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-remove.spec.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-remove.spec.ts @@ -1,5 +1,4 @@ import assert from 'assert'; -import fs from 'fs'; import sinon from 'sinon'; import auth from '../../../../Auth.js'; import { cli } from '../../../../cli/cli.js'; @@ -12,12 +11,13 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsetting-remove.js'; +import command, { options } from './groupsetting-remove.js'; describe(commands.GROUPSETTING_REMOVE, () => { let log: string[]; let logger: Logger; let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; let promptIssued: boolean = false; before(() => { @@ -25,9 +25,9 @@ describe(commands.GROUPSETTING_REMOVE, () => { sinon.stub(telemetry, 'trackEvent').resolves(); sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); - sinon.stub(fs, 'readFileSync').returns('abc'); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -81,7 +81,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848', force: true } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '28beab62-7540-4db1-a23f-29a6018a3848', force: true }) }); assert(deleteRequestStub.called); }); @@ -94,18 +94,18 @@ describe(commands.GROUPSETTING_REMOVE, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848', force: true } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848', force: true }) }); assert(deleteRequestStub.called); }); 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' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(promptIssued); }); 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' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(promptIssued); }); @@ -113,14 +113,14 @@ describe(commands.GROUPSETTING_REMOVE, () => { it('aborts removing the group setting when prompt not confirmed', async () => { const postSpy = sinon.spy(request, 'delete'); - await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(postSpy.notCalled); }); it('aborts removing the group setting when prompt not confirmed (debug)', async () => { const postSpy = sinon.spy(request, 'delete'); - await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(postSpy.notCalled); }); @@ -130,7 +130,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { sinonUtil.restore(cli.promptForConfirmation); sinon.stub(cli, 'promptForConfirmation').resolves(true); - await command.action(logger, { options: { id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(postStub.called); }); @@ -140,7 +140,7 @@ describe(commands.GROUPSETTING_REMOVE, () => { sinonUtil.restore(cli.promptForConfirmation); sinon.stub(cli, 'promptForConfirmation').resolves(true); - await command.action(logger, { options: { debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' }) }); assert(deleteStub.called); }); @@ -149,39 +149,17 @@ describe(commands.GROUPSETTING_REMOVE, () => { error: { 'odata.error': { message: { value: 'File Not Found.' } } } }); - await assert.rejects(command.action(logger, { options: { force: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ force: true, id: '28beab62-7540-4db1-a23f-29a6018a3848' }) } as any), new CommandError('File Not Found.')); }); - it('supports specifying id', () => { - const options = command.options; - let containsOption = false; - options.forEach(o => { - if (o.option.indexOf('--id') > -1) { - containsOption = true; - } - }); - assert(containsOption); - }); - - it('supports specifying confirmation flag', () => { - const options = command.options; - let containsOption = false; - options.forEach(o => { - if (o.option.indexOf('--force') > -1) { - containsOption = true; - } - }); - assert(containsOption); - }); - - it('fails validation if the id is not a valid GUID', async () => { - const actual = await command.validate({ options: { id: 'abc' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if the id is not a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: 'abc' }); + assert.strictEqual(actual.success, false); }); - it('passes validation when the id is a valid GUID', async () => { - const actual = await command.validate({ options: { id: '2c1ba4c4-cd9b-4417-832f-92a34bc34b2a' } }, commandInfo); - assert.strictEqual(actual, true); + it('passes validation when the id is a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: '2c1ba4c4-cd9b-4417-832f-92a34bc34b2a' }); + assert.strictEqual(actual.success, true); }); }); diff --git a/src/m365/entra/commands/groupsetting/groupsetting-remove.ts b/src/m365/entra/commands/groupsetting/groupsetting-remove.ts index 7f89a7a3d03..001116f708b 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-remove.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-remove.ts @@ -1,20 +1,23 @@ +import { z } from 'zod'; import { cli } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; -import GlobalOptions from '../../../../GlobalOptions.js'; +import { globalOptionsZod } from '../../../../Command.js'; import request, { CliRequestOptions } from '../../../../request.js'; -import { validation } from '../../../../utils/validation.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.strictObject({ + ...globalOptionsZod.shape, + id: z.uuid().alias('i'), + force: z.boolean().optional().alias('f') +}); + +declare type Options = z.infer; + interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - id: string; - force?: boolean; -} - class EntraGroupSettingRemoveCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTING_REMOVE; @@ -24,43 +27,8 @@ class EntraGroupSettingRemoveCommand extends GraphCommand { return 'Removes the particular group setting'; } - constructor() { - super(); - - this.#initTelemetry(); - this.#initOptions(); - this.#initValidators(); - } - - #initTelemetry(): void { - this.telemetry.push((args: CommandArgs) => { - Object.assign(this.telemetryProperties, { - force: (!(!args.options.force)).toString() - }); - }); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-i, --id ' - }, - { - option: '-f, --force' - } - ); - } - - #initValidators(): void { - this.validators.push( - async (args: CommandArgs) => { - if (!validation.isValidGuid(args.options.id)) { - return `${args.options.id} is not a valid GUID`; - } - - return true; - } - ); + public get schema(): z.ZodType | undefined { + return options; } public async commandAction(logger: Logger, args: CommandArgs): Promise { diff --git a/src/m365/entra/commands/groupsetting/groupsetting-set.spec.ts b/src/m365/entra/commands/groupsetting/groupsetting-set.spec.ts index 19ea4347cc3..7252813f719 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-set.spec.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-set.spec.ts @@ -12,12 +12,14 @@ import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; import command from './groupsetting-set.js'; +import { options } from './groupsetting-set.js'; describe(commands.GROUPSETTING_SET, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -26,6 +28,7 @@ describe(commands.GROUPSETTING_SET, () => { sinon.stub(session, 'getId').returns(''); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -142,12 +145,12 @@ describe(commands.GROUPSETTING_SET, () => { }); await command.action(logger, { - options: { + options: commandOptionsSchema.parse({ id: 'c391b57d-5783-4c53-9236-cefb5c6ef323', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' - } + }) }); assert(loggerLogSpy.notCalled); }); @@ -236,13 +239,13 @@ describe(commands.GROUPSETTING_SET, () => { }); await command.action(logger, { - options: { + options: commandOptionsSchema.parse({ debug: true, id: 'c391b57d-5783-4c53-9236-cefb5c6ef323', UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' - } + }) }); assert(settingsUpdated); }); @@ -329,7 +332,7 @@ describe(commands.GROUPSETTING_SET, () => { }); await command.action(logger, { - options: { + options: commandOptionsSchema.parse({ debug: true, verbose: true, output: "text", @@ -337,7 +340,7 @@ describe(commands.GROUPSETTING_SET, () => { UsageGuidelinesUrl: 'https://contoso.sharepoint.com/sites/compliance', ClassificationList: 'HBI, MBI, LBI, GDPR', DefaultClassification: 'MBI' - } + }) }); assert.deepEqual(patchStub.firstCall.args[0].data, { displayName: null, @@ -379,18 +382,18 @@ describe(commands.GROUPSETTING_SET, () => { }); }); - await assert.rejects(command.action(logger, { options: { id: '62375ab9-6b52-47ed-826b-58e47e0e304c' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ id: '62375ab9-6b52-47ed-826b-58e47e0e304c' }) } as any), new CommandError(`Resource '62375ab9-6b52-47ed-826b-58e47e0e304c' does not exist or one of its queried reference-property objects are not present.`)); }); - it('fails validation if the id is not a valid GUID', async () => { - const actual = await command.validate({ options: { id: 'invalid' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if the id is not a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: 'invalid' }); + assert.strictEqual(actual.success, false); }); - it('passes validation if the id is a valid GUID', async () => { - const actual = await command.validate({ options: { id: '68be84bf-a585-4776-80b3-30aa5207aa22' } }, commandInfo); - assert.strictEqual(actual, true); + it('passes validation if the id is a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: '68be84bf-a585-4776-80b3-30aa5207aa22' }); + assert.strictEqual(actual.success, true); }); it('allows unknown properties', () => { diff --git a/src/m365/entra/commands/groupsetting/groupsetting-set.ts b/src/m365/entra/commands/groupsetting/groupsetting-set.ts index 78be6f8c18d..d8c4708cda6 100644 --- a/src/m365/entra/commands/groupsetting/groupsetting-set.ts +++ b/src/m365/entra/commands/groupsetting/groupsetting-set.ts @@ -1,19 +1,22 @@ import { GroupSetting } from '@microsoft/microsoft-graph-types'; +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; -import GlobalOptions from '../../../../GlobalOptions.js'; +import { globalOptionsZod } from '../../../../Command.js'; import request, { CliRequestOptions } from '../../../../request.js'; -import { validation } from '../../../../utils/validation.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.looseObject({ + ...globalOptionsZod.shape, + id: z.uuid().alias('i') +}); + +declare type Options = z.infer; + interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - id: string; -} - class EntraGroupSettingSetCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTING_SET; @@ -27,31 +30,8 @@ class EntraGroupSettingSetCommand extends GraphCommand { return true; } - constructor() { - super(); - - this.#initOptions(); - this.#initValidators(); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-i, --id ' - } - ); - } - - #initValidators(): void { - this.validators.push( - async (args: CommandArgs) => { - if (!validation.isValidGuid(args.options.id)) { - return `${args.options.id} is not a valid GUID`; - } - - return true; - } - ); + public get schema(): z.ZodType | undefined { + return options; } public async commandAction(logger: Logger, args: CommandArgs): Promise { diff --git a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.spec.ts b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.spec.ts index ca0bc1c559c..3ddf879bc44 100644 --- a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.spec.ts +++ b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.spec.ts @@ -11,14 +11,14 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsettingtemplate-get.js'; -import { settingsNames } from '../../../../settingsNames.js'; +import command, { options } from './groupsettingtemplate-get.js'; describe(commands.GROUPSETTINGTEMPLATE_GET, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -27,6 +27,7 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { sinon.stub(session, 'getId').returns(''); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -48,8 +49,7 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { afterEach(() => { sinonUtil.restore([ - request.get, - cli.getSettingWithDefaultValue + request.get ]); }); @@ -75,7 +75,7 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { id: '62375ab9-6b52-47ed-826b-58e47e0e304b' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ id: '62375ab9-6b52-47ed-826b-58e47e0e304b' }) }); assert(loggerLogSpy.calledWith({ "id": "62375ab9-6b52-47ed-826b-58e47e0e304b", "deletedDateTime": null, "displayName": "Group.Unified", "description": "\n Setting templates define the different settings that can be used for the associated ObjectSettings. This template defines\n settings that can be used for Unified Groups.\n ", "values": [{ "name": "CustomBlockedWordsList", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of blocked words for Unified Group displayName and mailNickName." }, { "name": "EnableMSStandardBlockedWords", "type": "System.Boolean", "defaultValue": "false", "description": "A flag indicating whether or not to enable the Microsoft Standard list of blocked words for Unified Group displayName and mailNickName." }, { "name": "ClassificationDescriptions", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of structured strings describing the classification values in the ClassificationList. The structure of the string is: Value: Description" }, { "name": "DefaultClassification", "type": "System.String", "defaultValue": "", "description": "The classification value to be used by default for Unified Group creation." }, { "name": "PrefixSuffixNamingRequirement", "type": "System.String", "defaultValue": "", "description": "A structured string describing how a Unified Group displayName and mailNickname should be structured. Please refer to docs to discover how to structure a valid requirement." }, { "name": "AllowGuestsToBeGroupOwner", "type": "System.Boolean", "defaultValue": "false", "description": "Flag indicating if guests are allowed to be owner in any Unified Group." }, { "name": "AllowGuestsToAccessGroups", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if guests are allowed to access any Unified Group resources." }, { "name": "GuestUsageGuidelinesUrl", "type": "System.String", "defaultValue": "", "description": "A link to the Group Usage Guidelines for guests." }, { "name": "GroupCreationAllowedGroupId", "type": "System.Guid", "defaultValue": "", "description": "Guid of the security group that is always allowed to create Unified Groups." }, { "name": "AllowToAddGuests", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if guests are allowed in any Unified Group." }, { "name": "UsageGuidelinesUrl", "type": "System.String", "defaultValue": "", "description": "A link to the Group Usage Guidelines." }, { "name": "ClassificationList", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of valid classification values that can be applied to Unified Groups." }, { "name": "EnableGroupCreation", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if group creation feature is on." }] })); }); @@ -88,7 +88,7 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { debug: true, displayName: 'Group.Unified' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ debug: true, displayName: 'Group.Unified' }) }); assert(loggerLogSpy.calledWith({ "id": "62375ab9-6b52-47ed-826b-58e47e0e304b", "deletedDateTime": null, "displayName": "Group.Unified", "description": "\n Setting templates define the different settings that can be used for the associated ObjectSettings. This template defines\n settings that can be used for Unified Groups.\n ", "values": [{ "name": "CustomBlockedWordsList", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of blocked words for Unified Group displayName and mailNickName." }, { "name": "EnableMSStandardBlockedWords", "type": "System.Boolean", "defaultValue": "false", "description": "A flag indicating whether or not to enable the Microsoft Standard list of blocked words for Unified Group displayName and mailNickName." }, { "name": "ClassificationDescriptions", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of structured strings describing the classification values in the ClassificationList. The structure of the string is: Value: Description" }, { "name": "DefaultClassification", "type": "System.String", "defaultValue": "", "description": "The classification value to be used by default for Unified Group creation." }, { "name": "PrefixSuffixNamingRequirement", "type": "System.String", "defaultValue": "", "description": "A structured string describing how a Unified Group displayName and mailNickname should be structured. Please refer to docs to discover how to structure a valid requirement." }, { "name": "AllowGuestsToBeGroupOwner", "type": "System.Boolean", "defaultValue": "false", "description": "Flag indicating if guests are allowed to be owner in any Unified Group." }, { "name": "AllowGuestsToAccessGroups", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if guests are allowed to access any Unified Group resources." }, { "name": "GuestUsageGuidelinesUrl", "type": "System.String", "defaultValue": "", "description": "A link to the Group Usage Guidelines for guests." }, { "name": "GroupCreationAllowedGroupId", "type": "System.Guid", "defaultValue": "", "description": "Guid of the security group that is always allowed to create Unified Groups." }, { "name": "AllowToAddGuests", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if guests are allowed in any Unified Group." }, { "name": "UsageGuidelinesUrl", "type": "System.String", "defaultValue": "", "description": "A link to the Group Usage Guidelines." }, { "name": "ClassificationList", "type": "System.String", "defaultValue": "", "description": "A comma-delimited list of valid classification values that can be applied to Unified Groups." }, { "name": "EnableGroupCreation", "type": "System.Boolean", "defaultValue": "true", "description": "Flag indicating if group creation feature is on." }] })); }); @@ -101,7 +101,7 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { throw 'Invalid request'; }); - await assert.rejects(command.action(logger, { options: { id: '62375ab9-6b52-47ed-826b-58e47e0e304c' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ id: '62375ab9-6b52-47ed-826b-58e47e0e304c' }) } as any), new CommandError(`Resource '62375ab9-6b52-47ed-826b-58e47e0e304c' does not exist.`)); }); @@ -114,55 +114,39 @@ describe(commands.GROUPSETTINGTEMPLATE_GET, () => { throw 'Invalid request'; }); - await assert.rejects(command.action(logger, { options: { displayName: 'Invalid' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Invalid' }) } as any), new CommandError(`Resource 'Invalid' does not exist.`)); }); it('handles error correctly', async () => { sinon.stub(request, 'get').rejects(new Error('An error has occurred')); - await assert.rejects(command.action(logger, { options: { displayName: 'Invalid' } } as any), + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Invalid' }) } as any), new CommandError('An error has occurred')); }); - it('fails validation if neither the id nor the displayName are specified', async () => { - sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { - if (settingName === settingsNames.prompt) { - return false; - } - - return defaultValue; - }); - - const actual = await command.validate({ options: {} }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if neither the id nor the displayName are specified', () => { + const actual = commandOptionsSchema.safeParse({}); + assert.strictEqual(actual.success, false); }); - it('fails validation if both the id and the displayName are specified', async () => { - sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => { - if (settingName === settingsNames.prompt) { - return false; - } - - return defaultValue; - }); - - const actual = await command.validate({ options: { id: '68be84bf-a585-4776-80b3-30aa5207aa22', displayName: 'Group.Unified' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if both the id and the displayName are specified', () => { + const actual = commandOptionsSchema.safeParse({ id: '68be84bf-a585-4776-80b3-30aa5207aa22', displayName: 'Group.Unified' }); + assert.strictEqual(actual.success, false); }); - it('fails validation if the id is not a valid GUID', async () => { - const actual = await command.validate({ options: { id: 'invalid' } }, commandInfo); - assert.notStrictEqual(actual, true); + it('fails validation if the id is not a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: 'invalid' }); + assert.strictEqual(actual.success, false); }); - it('passes validation if the id is a valid GUID', async () => { - const actual = await command.validate({ options: { id: '68be84bf-a585-4776-80b3-30aa5207aa22' } }, commandInfo); - assert.strictEqual(actual, true); + it('passes validation if the id is a valid GUID', () => { + const actual = commandOptionsSchema.safeParse({ id: '68be84bf-a585-4776-80b3-30aa5207aa22' }); + assert.strictEqual(actual.success, true); }); - it('passes validation if the displayName is specified', async () => { - const actual = await command.validate({ options: { displayName: 'Group.Unified' } }, commandInfo); - assert.strictEqual(actual, true); + it('passes validation if the displayName is specified', () => { + const actual = commandOptionsSchema.safeParse({ displayName: 'Group.Unified' }); + assert.strictEqual(actual.success, true); }); }); diff --git a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.ts b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.ts index 13646081cd8..07974bfea15 100644 --- a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.ts +++ b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-get.ts @@ -1,20 +1,23 @@ import { GroupSettingTemplate } from '@microsoft/microsoft-graph-types'; +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; -import GlobalOptions from '../../../../GlobalOptions.js'; +import { globalOptionsZod } from '../../../../Command.js'; import { odata } from '../../../../utils/odata.js'; -import { validation } from '../../../../utils/validation.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.strictObject({ + ...globalOptionsZod.shape, + id: z.uuid().optional().alias('i'), + displayName: z.string().optional().alias('n') +}); + +declare type Options = z.infer; + interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - id?: string; - displayName?: string; -} - class EntraGroupSettingTemplateGetCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTINGTEMPLATE_GET; @@ -24,50 +27,19 @@ class EntraGroupSettingTemplateGetCommand extends GraphCommand { return 'Gets information about the specified Entra group settings template'; } - constructor() { - super(); - - this.#initTelemetry(); - this.#initOptions(); - this.#initValidators(); - this.#initOptionSets(); - } - - #initTelemetry(): void { - this.telemetry.push((args: CommandArgs) => { - Object.assign(this.telemetryProperties, { - id: typeof args.options.id !== 'undefined', - displayName: typeof args.options.displayName !== 'undefined' - }); - }); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-i, --id [id]' - }, - { - option: '-n, --displayName [displayName]' - } - ); + public get schema(): z.ZodType | undefined { + return options; } - #initValidators(): void { - this.validators.push( - async (args: CommandArgs) => { - if (args.options.id && - !validation.isValidGuid(args.options.id)) { - return `${args.options.id} is not a valid GUID`; + public getRefinedSchema(schema: typeof options): z.ZodObject | undefined { + return schema + .refine(options => [options.id, options.displayName].filter(Boolean).length === 1, { + error: 'Specify either id or displayName', + params: { + customCode: 'optionSet', + options: ['id', 'displayName'] } - - return true; - } - ); - } - - #initOptionSets(): void { - this.optionSets.push({ options: ['id', 'displayName'] }); + }); } public async commandAction(logger: Logger, args: CommandArgs): Promise { diff --git a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.spec.ts b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.spec.ts index 75aa42838f1..3c2a3748c95 100644 --- a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.spec.ts +++ b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.spec.ts @@ -1,6 +1,8 @@ import assert from 'assert'; import sinon from 'sinon'; import auth from '../../../../Auth.js'; +import { cli } from '../../../../cli/cli.js'; +import { CommandInfo } from '../../../../cli/CommandInfo.js'; import { Logger } from '../../../../cli/Logger.js'; import { CommandError } from '../../../../Command.js'; import request from '../../../../request.js'; @@ -9,12 +11,14 @@ import { pid } from '../../../../utils/pid.js'; import { session } from '../../../../utils/session.js'; import { sinonUtil } from '../../../../utils/sinonUtil.js'; import commands from '../../commands.js'; -import command from './groupsettingtemplate-list.js'; +import command, { options } from './groupsettingtemplate-list.js'; describe(commands.GROUPSETTINGTEMPLATE_LIST, () => { let log: string[]; let logger: Logger; let loggerLogSpy: sinon.SinonSpy; + let commandInfo: CommandInfo; + let commandOptionsSchema: typeof options; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -22,6 +26,8 @@ describe(commands.GROUPSETTINGTEMPLATE_LIST, () => { sinon.stub(pid, 'getProcessName').returns(''); sinon.stub(session, 'getId').returns(''); auth.connection.active = true; + commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options; }); beforeEach(() => { @@ -64,6 +70,16 @@ describe(commands.GROUPSETTINGTEMPLATE_LIST, () => { assert.deepStrictEqual(command.defaultProperties(), ['id', 'displayName']); }); + it('passes validation with no options', () => { + const actual = commandOptionsSchema.safeParse({}); + assert.strictEqual(actual.success, true); + }); + + it('fails validation with unknown options', () => { + const actual = commandOptionsSchema.safeParse({ unknownOption: 'value' }); + assert.strictEqual(actual.success, false); + }); + it('lists group setting templates', async () => { sinon.stub(request, 'get').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/groupSettingTemplates`) { diff --git a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.ts b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.ts index 301d0654cd6..61fce91f149 100644 --- a/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.ts +++ b/src/m365/entra/commands/groupsettingtemplate/groupsettingtemplate-list.ts @@ -1,9 +1,13 @@ import { GroupSettingTemplate } from '@microsoft/microsoft-graph-types'; +import { z } from 'zod'; import { Logger } from '../../../../cli/Logger.js'; +import { globalOptionsZod } from '../../../../Command.js'; import { odata } from '../../../../utils/odata.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; +export const options = z.strictObject({ ...globalOptionsZod.shape }); + class EntraGroupSettingTemplateListCommand extends GraphCommand { public get name(): string { return commands.GROUPSETTINGTEMPLATE_LIST; @@ -17,6 +21,10 @@ class EntraGroupSettingTemplateListCommand extends GraphCommand { return ['id', 'displayName']; } + public get schema(): z.ZodType | undefined { + return options; + } + public async commandAction(logger: Logger): Promise { try { const templates = await odata.getAllItems(`${this.resource}/v1.0/groupSettingTemplates`);