Skip to content

Commit 071c745

Browse files
Updates prompt file for zod migration
1 parent b1eeb91 commit 071c745

File tree

1 file changed

+215
-2
lines changed

1 file changed

+215
-2
lines changed

.github/prompts/migrate-command-to-zod.prompt.md

Lines changed: 215 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,218 @@ Update the command file to use ZOD.
1111

1212
Use the below git commits as reference implementations for a command and its tests using ZOD. Do not continue with the task if you do not have access to these commits.
1313

14-
- 824c1ebd2dfb0a1eabb623ed6a22da50f4edf61d
15-
- 3410857272d39e16fe498823a1df9f320b1021dd
14+
```diff
15+
commit 824c1ebd2dfb0a1eabb623ed6a22da50f4edf61d
16+
Author: waldekmastykarz <[email protected]>
17+
Date: Sun Apr 20 09:02:32 2025 +0200
18+
19+
diff --git a/src/m365/booking/commands/business/business-get.spec.ts b/src/m365/booking/commands/business/business-get.spec.ts
20+
index 40b3c3d2a..9c4f21496 100644
21+
--- a/src/m365/booking/commands/business/business-get.spec.ts
22+
+++ b/src/m365/booking/commands/business/business-get.spec.ts
23+
@@ -1,10 +1,13 @@
24+
import assert from 'assert';
25+
import sinon from 'sinon';
26+
+import { z } from 'zod';
27+
import auth from '../../../../Auth.js';
28+
import { cli } from '../../../../cli/cli.js';
29+
+import { CommandInfo } from '../../../../cli/CommandInfo.js';
30+
import { Logger } from '../../../../cli/Logger.js';
31+
import { CommandError } from '../../../../Command.js';
32+
import request from '../../../../request.js';
33+
+import { settingsNames } from '../../../../settingsNames.js';
34+
import { telemetry } from '../../../../telemetry.js';
35+
import { formatting } from '../../../../utils/formatting.js';
36+
import { pid } from '../../../../utils/pid.js';
37+
@@ -12,7 +15,6 @@ import { session } from '../../../../utils/session.js';
38+
import { sinonUtil } from '../../../../utils/sinonUtil.js';
39+
import commands from '../../commands.js';
40+
import command from './business-get.js';
41+
-import { settingsNames } from '../../../../settingsNames.js';
42+
43+
describe(commands.BUSINESS_GET, () => {
44+
const validId = '[email protected]';
45+
@@ -31,6 +33,8 @@ describe(commands.BUSINESS_GET, () => {
46+
let log: string[];
47+
let logger: Logger;
48+
let loggerLogSpy: sinon.SinonSpy;
49+
+ let commandInfo: CommandInfo;
50+
+ let commandOptionsSchema: z.ZodTypeAny;
51+
52+
before(() => {
53+
sinon.stub(auth, 'restoreAuth').resolves();
54+
@@ -39,6 +43,8 @@ describe(commands.BUSINESS_GET, () => {
55+
sinon.stub(session, 'getId').returns('');
56+
57+
auth.connection.active = true;
58+
+ commandInfo = cli.getCommandInfo(command);
59+
+ commandOptionsSchema = commandInfo.command.getSchemaToParse()!;
60+
});
61+
62+
beforeEach(() => {
63+
@@ -80,6 +86,25 @@ describe(commands.BUSINESS_GET, () => {
64+
assert.notStrictEqual(command.description, null);
65+
});
66+
67+
+ it('fails validation when id or name are not specified', () => {
68+
+ const actual = commandOptionsSchema.safeParse({});
69+
+ assert.strictEqual(actual.success, false);
70+
+ });
71+
+
72+
+ it('passes validation when id is specified', () => {
73+
+ const actual = commandOptionsSchema.safeParse({
74+
+ id: validId
75+
+ });
76+
+ assert.strictEqual(actual.success, true);
77+
+ });
78+
+
79+
+ it('passes validation when name is specified', () => {
80+
+ const actual = commandOptionsSchema.safeParse({
81+
+ name: validName
82+
+ });
83+
+ assert.strictEqual(actual.success, true);
84+
+ });
85+
+
86+
it('gets business by id', async () => {
87+
sinon.stub(request, 'get').callsFake(async (opts) => {
88+
if (opts.url === `https://graph.microsoft.com/v1.0/solutions/bookingBusinesses/${formatting.encodeQueryParameter(validId)}`) {
89+
@@ -89,7 +114,7 @@ describe(commands.BUSINESS_GET, () => {
90+
throw 'Invalid request';
91+
});
92+
93+
- await command.action(logger, { options: { id: validId } });
94+
+ await command.action(logger, { options: commandOptionsSchema.parse({ id: validId }) });
95+
assert(loggerLogSpy.calledWith(businessResponse));
96+
});
97+
98+
@@ -106,7 +131,7 @@ describe(commands.BUSINESS_GET, () => {
99+
throw 'Invalid request';
100+
});
101+
102+
- await command.action(logger, { options: { name: validName } });
103+
+ await command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) });
104+
assert(loggerLogSpy.calledWith(businessResponse));
105+
});
106+
107+
@@ -127,7 +152,7 @@ describe(commands.BUSINESS_GET, () => {
108+
throw 'Invalid request';
109+
});
110+
111+
- await assert.rejects(command.action(logger, { options: { name: validName } } as any), new CommandError("Multiple businesses with name 'Valid Business' found. Found: [email protected]."));
112+
+ await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) }), new CommandError("Multiple businesses with name 'Valid Business' found. Found: [email protected]."));
113+
});
114+
115+
it('handles selecting single result when multiple businesses with the specified name found and cli is set to prompt', async () => {
116+
@@ -153,7 +178,7 @@ describe(commands.BUSINESS_GET, () => {
117+
118+
sinon.stub(cli, 'handleMultipleResultsFound').resolves(businessResponse);
119+
120+
- await command.action(logger, { options: { name: validName } });
121+
+ await command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) });
122+
assert(loggerLogSpy.calledWith(businessResponse));
123+
});
124+
125+
@@ -166,7 +191,7 @@ describe(commands.BUSINESS_GET, () => {
126+
throw 'Invalid request';
127+
});
128+
129+
- await assert.rejects(command.action(logger, { options: { name: validName } } as any), new CommandError(`The specified business with name ${validName} does not exist.`));
130+
+ await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) } as any), new CommandError(`The specified business with name ${validName} does not exist.`));
131+
});
132+
133+
it('fails when no business found with name because of an empty displayName', async () => {
134+
@@ -178,13 +203,13 @@ describe(commands.BUSINESS_GET, () => {
135+
throw 'Invalid request';
136+
});
137+
138+
- await assert.rejects(command.action(logger, { options: { name: validName } } as any), new CommandError(`The specified business with name ${validName} does not exist.`));
139+
+ await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) } as any), new CommandError(`The specified business with name ${validName} does not exist.`));
140+
});
141+
142+
it('correctly handles random API error', async () => {
143+
sinonUtil.restore(request.get);
144+
sinon.stub(request, 'get').rejects(new Error('An error has occurred'));
145+
- await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('An error has occurred'));
146+
+ await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ name: validName }) } as any), new CommandError('An error has occurred'));
147+
});
148+
});
149+
150+
diff --git a/src/m365/booking/commands/business/business-get.ts b/src/m365/booking/commands/business/business-get.ts
151+
index 5a066ea56..bace8b52c 100644
152+
--- a/src/m365/booking/commands/business/business-get.ts
153+
+++ b/src/m365/booking/commands/business/business-get.ts
154+
@@ -1,21 +1,27 @@
155+
import { BookingBusiness } from '@microsoft/microsoft-graph-types';
156+
+import { z } from 'zod';
157+
+import { cli } from '../../../../cli/cli.js';
158+
import { Logger } from '../../../../cli/Logger.js';
159+
-import GlobalOptions from '../../../../GlobalOptions.js';
160+
+import { globalOptionsZod } from '../../../../Command.js';
161+
import request, { CliRequestOptions } from '../../../../request.js';
162+
import { formatting } from '../../../../utils/formatting.js';
163+
+import { zod } from '../../../../utils/zod.js';
164+
import GraphCommand from '../../../base/GraphCommand.js';
165+
import commands from '../../commands.js';
166+
-import { cli } from '../../../../cli/cli.js';
167+
+
168+
+const options = globalOptionsZod
169+
+ .extend({
170+
+ id: zod.alias('i', z.string().uuid().optional()),
171+
+ name: zod.alias('n', z.string().optional())
172+
+ })
173+
+ .strict();
174+
+
175+
+declare type Options = z.infer<typeof options>;
176+
177+
interface CommandArgs {
178+
options: Options;
179+
}
180+
181+
-interface Options extends GlobalOptions {
182+
- id?: string;
183+
- name?: string;
184+
-}
185+
-
186+
class BookingBusinessGetCommand extends GraphCommand {
187+
public get name(): string {
188+
return commands.BUSINESS_GET;
189+
@@ -25,32 +31,15 @@ class BookingBusinessGetCommand extends GraphCommand {
190+
return 'Retrieve the specified Microsoft Bookings business.';
191+
}
192+
193+
- constructor() {
194+
- super();
195+
-
196+
- this.#initTelemetry();
197+
- this.#initOptions();
198+
- this.#initOptionSets();
199+
+ public get schema(): z.ZodTypeAny | undefined {
200+
+ return options;
201+
}
202+
203+
- #initTelemetry(): void {
204+
- this.telemetry.push((args: CommandArgs) => {
205+
- Object.assign(this.telemetryProperties, {
206+
- id: typeof args.options.id !== 'undefined',
207+
- name: typeof args.options.name !== 'undefined'
208+
+ public getRefinedSchema(schema: typeof options): z.ZodEffects<any> | undefined {
209+
+ return schema
210+
+ .refine(options => [options.id, options.name].filter(Boolean).length === 1, {
211+
+ message: 'Specify either id or name'
212+
});
213+
- });
214+
- }
215+
-
216+
- #initOptions(): void {
217+
- this.options.unshift(
218+
- { option: '-i, --id [id]' },
219+
- { option: '-n, --name [name]' }
220+
- );
221+
- }
222+
-
223+
- #initOptionSets(): void {
224+
- this.optionSets.push({ options: ['id', 'name'] });
225+
}
226+
227+
public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
228+
```

0 commit comments

Comments
 (0)