Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .impeccable/hook.cache.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"version":1,"sessions":{"fed13f1e-d806-4acd-93c5-8e6ad9fbf7fd":{"updatedAt":1782377072287,"files":{"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-get.ts":{"editCount":1,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-remove.ts":{"editCount":1,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-add.ts":{"editCount":2,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-set.ts":{"editCount":2,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-get.spec.ts":{"editCount":1,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-remove.spec.ts":{"editCount":1,"findings":[]},"/Users/waldek/.copilot/copilot-worktrees/cli-microsoft365/waldekmastykarz-refactored-giggle/src/m365/planner/commands/task/task-add.spec.ts":{"editCount":2,"findings":[]}}}}}
Comment thread
waldekmastykarz marked this conversation as resolved.
Outdated
26 changes: 22 additions & 4 deletions src/m365/planner/commands/roster/roster-add.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -10,17 +12,19 @@ import { session } from '../../../../utils/session.js';
import { powerPlatform } from '../../../../utils/powerPlatform.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command from './roster-add.js';
import command, { options } from './roster-add.js';

describe(commands.ROSTER_ADD, () => {
const rosterResponse = {
id: "8bc07d47-c06f-41e1-8f00-1c113c8f6067",
id: '8bc07d47-c06f-41e1-8f00-1c113c8f6067',
assignedSensitivityLabel: null
};

let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
Expand All @@ -32,6 +36,8 @@ describe(commands.ROSTER_ADD, () => {
accessToken: 'abc',
expiresOn: new Date()
};
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

beforeEach(() => {
Expand Down Expand Up @@ -70,6 +76,18 @@ describe(commands.ROSTER_ADD, () => {
assert.notStrictEqual(command.description, null);
});

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('adds a new roster', async () => {
sinon.stub(request, 'post').callsFake(async opts => {
if (opts.url === 'https://graph.microsoft.com/beta/planner/rosters') {
Expand All @@ -79,15 +97,15 @@ describe(commands.ROSTER_ADD, () => {
throw `Invalid request ${opts.url}`;
});

await command.action(logger, { options: { verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ verbose: true }) });
assert(loggerLogSpy.calledWith(rosterResponse));
});

it('correctly handles random API error', async () => {
sinon.stub(request, 'post').rejects(new Error('An error has occurred'));

await assert.rejects(command.action(logger, {
options: {}
options: commandOptionsSchema.parse({})
}), new CommandError('An error has occurred'));
});
});
11 changes: 9 additions & 2 deletions src/m365/planner/commands/roster/roster-add.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { z } from 'zod';
import { globalOptionsZod } from '../../../../Command.js';
import { Logger } from '../../../../cli/Logger.js';
import request, { CliRequestOptions } from '../../../../request.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';

export const options = globalOptionsZod.strict();

class PlannerRosterAddCommand extends GraphCommand {
public get name(): string {
return commands.ROSTER_ADD;
Expand All @@ -12,6 +16,10 @@ class PlannerRosterAddCommand extends GraphCommand {
return 'Creates a new Microsoft Planner Roster';
}

public get schema(): z.ZodType | undefined {
return options;
}

public async commandAction(logger: Logger): Promise<void> {
if (this.verbose) {
await logger.logToStderr('Creating a new Microsoft Planner Roster');
Expand All @@ -34,7 +42,6 @@ class PlannerRosterAddCommand extends GraphCommand {
this.handleRejectedODataJsonPromise(err);
}
}

}

export default new PlannerRosterAddCommand();
export default new PlannerRosterAddCommand();
35 changes: 28 additions & 7 deletions src/m365/planner/commands/roster/roster-get.spec.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -9,25 +11,29 @@ 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 './roster-get.js';
import command, { options } from './roster-get.js';

describe(commands.ROSTER_GET, () => {
const id = '8bc07d47-c06f-41e1-8f00-1c113c8f6067';
const rosterGetResponse = {
"id": id,
"assignedSensitivityLabel": null
id: id,
assignedSensitivityLabel: null
};

let log: any[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').resolves();
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(() => {
Expand Down Expand Up @@ -65,6 +71,21 @@ describe(commands.ROSTER_GET, () => {
assert.notStrictEqual(command.description, null);
});

it('passes validation with valid id', () => {
const actual = commandOptionsSchema.safeParse({
id
});
assert.strictEqual(actual.success, true);
});

it('fails validation with unknown options', () => {
const actual = commandOptionsSchema.safeParse({
id,
unknownOption: 'value'
});
assert.strictEqual(actual.success, false);
});

it('retrieves Microsoft Planner Roster by specified id', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/beta/planner/rosters/${id}`) {
Expand All @@ -74,7 +95,7 @@ describe(commands.ROSTER_GET, () => {
throw 'Invalid request';
});

await command.action(logger, { options: { id: id, verbose: true } });
await command.action(logger, { options: commandOptionsSchema.parse({ id, verbose: true }) });
assert(loggerLogSpy.calledWith(rosterGetResponse));
});

Expand All @@ -89,10 +110,10 @@ describe(commands.ROSTER_GET, () => {
});

await assert.rejects(command.action(logger, {
options: {
options: commandOptionsSchema.parse({
debug: true,
id: id
}
id
})
}), new CommandError(errorMessage));
});
});
35 changes: 12 additions & 23 deletions src/m365/planner/commands/roster/roster-get.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { z } from 'zod';
import { globalOptionsZod } from '../../../../Command.js';
import { Logger } from '../../../../cli/Logger.js';
import GlobalOptions from '../../../../GlobalOptions.js';
import request, { CliRequestOptions } from '../../../../request.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';

export const options = z.strictObject({
...globalOptionsZod.shape,
id: z.string()
});

declare type Options = z.infer<typeof options>;

interface CommandArgs {
options: Options;
}

interface Options extends GlobalOptions {
id: string;
}

class PlannerRosterGetCommand extends GraphCommand {
public get name(): string {
return commands.ROSTER_GET;
Expand All @@ -21,23 +25,8 @@ class PlannerRosterGetCommand extends GraphCommand {
return 'Retrieve information about a specific Microsoft Planner Roster';
}

constructor() {
super();

this.#initOptions();
this.#initTypes();
}

#initOptions(): void {
this.options.unshift(
{
option: '--id <id>'
}
);
}

#initTypes(): void {
this.types.string.push('id');
public get schema(): z.ZodType | undefined {
return options;
}

public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand All @@ -63,4 +52,4 @@ class PlannerRosterGetCommand extends GraphCommand {
}
}

export default new PlannerRosterGetCommand();
export default new PlannerRosterGetCommand();
Loading
Loading