Skip to content

Commit b46e017

Browse files
authored
Migrates 'entra multitenant add' to Zod. Closes #6906
1 parent 0432e1f commit b46e017

File tree

2 files changed

+23
-44
lines changed

2 files changed

+23
-44
lines changed

src/m365/entra/commands/multitenant/multitenant-add.spec.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert from 'assert';
22
import sinon from 'sinon';
3+
import { z } from 'zod';
34
import auth from '../../../../Auth.js';
45
import { cli } from '../../../../cli/cli.js';
56
import { CommandInfo } from '../../../../cli/CommandInfo.js';
@@ -33,6 +34,7 @@ describe(commands.MULTITENANT_ADD, () => {
3334
let logger: Logger;
3435
let loggerLogSpy: sinon.SinonSpy;
3536
let commandInfo: CommandInfo;
37+
let commandOptionsSchema: z.ZodTypeAny;
3638

3739
before(() => {
3840
sinon.stub(auth, 'restoreAuth').resolves();
@@ -41,6 +43,7 @@ describe(commands.MULTITENANT_ADD, () => {
4143
sinon.stub(session, 'getId').returns('');
4244
auth.connection.active = true;
4345
commandInfo = cli.getCommandInfo(command);
46+
commandOptionsSchema = commandInfo.command.getSchemaToParse()!;
4447
});
4548

4649
beforeEach(() => {
@@ -80,13 +83,13 @@ describe(commands.MULTITENANT_ADD, () => {
8083
});
8184

8285
it('passes validation when only displayName is specified', async () => {
83-
const actual = await command.validate({ options: { displayName: 'Contoso organization' } }, commandInfo);
84-
assert.strictEqual(actual, true);
86+
const parseResult = commandOptionsSchema.safeParse({ displayName: 'Contoso organization' });
87+
assert.strictEqual(parseResult.success, true);
8588
});
8689

8790
it('passes validation when the displayName and description are specified', async () => {
88-
const actual = await command.validate({ options: { displayName: 'Contoso organization', description: 'Contoso and partners' } }, commandInfo);
89-
assert.strictEqual(actual, true);
91+
const parseResult = commandOptionsSchema.safeParse({ displayName: 'Contoso organization', description: 'Contoso and partners' });
92+
assert.strictEqual(parseResult.success, true);
9093
});
9194

9295
it('creates a multitenant organization with a displayName only', async () => {
@@ -98,7 +101,7 @@ describe(commands.MULTITENANT_ADD, () => {
98101
throw 'Invalid request';
99102
});
100103

101-
await command.action(logger, { options: { displayName: 'Contoso organization', verbose: true } });
104+
await command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization', verbose: true }) });
102105
assert(loggerLogSpy.calledOnceWithExactly(multitenantOrganizationShortReponse));
103106
});
104107

@@ -111,7 +114,7 @@ describe(commands.MULTITENANT_ADD, () => {
111114
throw 'Invalid request';
112115
});
113116

114-
await command.action(logger, { options: { displayName: 'Contoso organization', description: 'Contoso and partners' } });
117+
await command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization', description: 'Contoso and partners' }) });
115118
assert(loggerLogSpy.calledOnceWithExactly(multitenantOrganizationReponse));
116119
});
117120

@@ -127,7 +130,7 @@ describe(commands.MULTITENANT_ADD, () => {
127130
}
128131
});
129132

130-
await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('Invalid request'));
133+
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization' }) }), new CommandError('Invalid request'));
131134
});
132135

133136
it('correctly handles API OData error when the multitenant organization already exist', async () => {
@@ -143,6 +146,6 @@ describe(commands.MULTITENANT_ADD, () => {
143146
}
144147
});
145148

146-
await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('Method not supported for update operation.'));
149+
await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization' }) }), new CommandError('Method not supported for update operation.'));
147150
});
148151
});

src/m365/entra/commands/multitenant/multitenant-add.ts

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
import GlobalOptions from '../../../../GlobalOptions.js';
1+
import { z } from 'zod';
2+
import { globalOptionsZod } from '../../../../Command.js';
23
import { Logger } from '../../../../cli/Logger.js';
34
import request, { CliRequestOptions } from '../../../../request.js';
45
import GraphCommand from '../../../base/GraphCommand.js';
56
import commands from '../../commands.js';
67
import { MultitenantOrganization } from './MultitenantOrganization.js';
8+
import { zod } from '../../../../utils/zod.js';
9+
10+
const options = globalOptionsZod
11+
.extend({
12+
displayName: zod.alias('n', z.string()),
13+
description: zod.alias('d', z.string().optional())
14+
}).strict();
15+
declare type Options = z.infer<typeof options>;
716

817
interface CommandArgs {
918
options: Options;
1019
}
1120

12-
interface Options extends GlobalOptions {
13-
displayName: string;
14-
description?: string;
15-
}
16-
1721
class EntraMultitenantAddCommand extends GraphCommand {
1822
public get name(): string {
1923
return commands.MULTITENANT_ADD;
@@ -23,36 +27,8 @@ class EntraMultitenantAddCommand extends GraphCommand {
2327
return 'Creates a new multitenant organization';
2428
}
2529

26-
constructor() {
27-
super();
28-
29-
this.#initTelemetry();
30-
this.#initOptions();
31-
this.#initTypes();
32-
}
33-
34-
#initTelemetry(): void {
35-
this.telemetry.push((args: CommandArgs) => {
36-
Object.assign(this.telemetryProperties, {
37-
displayName: typeof args.options.displayName !== 'undefined',
38-
description: typeof args.options.description !== 'undefined'
39-
});
40-
});
41-
}
42-
43-
#initOptions(): void {
44-
this.options.unshift(
45-
{
46-
option: '-n, --displayName <displayName>'
47-
},
48-
{
49-
option: '-d, --description [description]'
50-
}
51-
);
52-
}
53-
54-
#initTypes(): void {
55-
this.types.string.push('displayName', 'description');
30+
public get schema(): z.ZodTypeAny | undefined {
31+
return options;
5632
}
5733

5834
public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {

0 commit comments

Comments
 (0)