Skip to content

Commit

Permalink
refactor: convert apps:authorize command to yargs
Browse files Browse the repository at this point in the history
  • Loading branch information
rossiam committed Dec 2, 2024
1 parent 49828f8 commit 6e8e829
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 90 deletions.
50 changes: 0 additions & 50 deletions packages/cli/src/__tests__/commands/apps/authorize.test.ts

This file was deleted.

40 changes: 0 additions & 40 deletions packages/cli/src/commands/apps/authorize.ts

This file was deleted.

81 changes: 81 additions & 0 deletions src/__tests__/commands/apps/authorize.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { jest } from '@jest/globals'

import type { ArgumentsCamelCase, Argv } from 'yargs'

import type { CommandArgs } from '../../../commands/apps/authorize.js'
import { addPermission } from '../../../lib/aws-util.js'
import type { lambdaAuthBuilder, LambdaAuthFlags } from '../../../lib/command/common-flags.js'
import type {
smartThingsCommand,
smartThingsCommandBuilder,
SmartThingsCommandFlags,
} from '../../../lib/command/smartthings-command.js'
import { buildArgvMock, buildArgvMockStub } from '../../test-lib/builder-mock.js'


const addPermissionMock = jest.fn<typeof addPermission>()
.mockResolvedValue('permissions updated')
jest.unstable_mockModule('../../../lib/aws-util.js', () => ({
addPermission: addPermissionMock,
}))

const lambdaAuthBuilderMock = jest.fn<typeof lambdaAuthBuilder>()
jest.unstable_mockModule('../../../lib/command/common-flags.js', () => ({
lambdaAuthBuilder: lambdaAuthBuilderMock,
}))

const smartThingsCommandMock = jest.fn<typeof smartThingsCommand>()
const smartThingsCommandBuilderMock = jest.fn<typeof smartThingsCommandBuilder>()
jest.unstable_mockModule('../../../lib/command/smartthings-command.js', () => ({
smartThingsCommand: smartThingsCommandMock,
smartThingsCommandBuilder: smartThingsCommandBuilderMock,
}))

const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { /*no-op*/ })


const { default: cmd } = await import('../../../commands/apps/authorize.js')


test('builder', () => {
const yargsMock = buildArgvMockStub<object>()
const {
yargsMock: smartThingsCommandBuilderArgvMock,
positionalMock,
epilogMock,
exampleMock,
argvMock,
} = buildArgvMock<SmartThingsCommandFlags, LambdaAuthFlags>()

smartThingsCommandBuilderMock.mockReturnValue(smartThingsCommandBuilderArgvMock)
lambdaAuthBuilderMock.mockReturnValueOnce(argvMock)

const builder = cmd.builder as (yargs: Argv<object>) => Argv<CommandArgs>
expect(builder(yargsMock)).toBe(argvMock)

expect(positionalMock).toHaveBeenCalledTimes(1)
expect(exampleMock).toHaveBeenCalledTimes(1)
expect(epilogMock).toHaveBeenCalledTimes(1)
})

describe('handler', () => {
const inputArgv =
{ profile: 'default', arn: 'arn' } as ArgumentsCamelCase<CommandArgs>

it('calls addPermission with specified ARN', async () => {
await expect(cmd.handler(inputArgv)).resolves.not.toThrow()

expect(addPermissionMock)
.toHaveBeenCalledExactlyOnceWith('arn', undefined, undefined)
expect(consoleLogSpy).toHaveBeenCalledWith('permissions updated')
})

it('passes on principal and statement', async () => {
await expect(cmd.handler(
{ ...inputArgv, principal: 'principal', statement: 'statement' },
)).resolves.not.toThrow()

expect(addPermissionMock)
.toHaveBeenCalledExactlyOnceWith('arn', 'principal', 'statement')
})
})
48 changes: 48 additions & 0 deletions src/commands/apps/authorize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { ArgumentsCamelCase, Argv, CommandModule } from 'yargs'

import { addPermission } from '../../lib/aws-util.js'
import { lambdaAuthBuilder, LambdaAuthFlags } from '../../lib/command/common-flags.js'
import {
smartThingsCommand,
smartThingsCommandBuilder,
SmartThingsCommandFlags,
} from '../../lib/command/smartthings-command.js'


export type CommandArgs = SmartThingsCommandFlags & LambdaAuthFlags & {
arn: string
}

const command = 'apps:authorize <arn>'

const describe = 'authorize calls to your AWS Lambda function from SmartThings'

const builder = (yargs: Argv): Argv<CommandArgs> =>
lambdaAuthBuilder(smartThingsCommandBuilder(yargs))
.positional(
'arn',
{ describe: 'the ARN of the AWS Lambda function', type: 'string', demandOption: true },
)
.example([
[
'$0 apps:authorize \\\n> arn:aws:lambda:us-east-1:1234567890:function:your-app',
'authorize an app',
],
])
.epilog(`NOTE: The example above is the same as running the following with the AWS CLI:
$ aws lambda add-permission --region us-east-1 --function-name \\
> arn:aws:lambda:us-east-1:1234567890:function:your-app \\
> --statement smartthings --principal 906037444270 --action lambda:InvokeFunction
This command requires your machine to be configured to run the AWS CLI.`)

const handler = async (argv: ArgumentsCamelCase<CommandArgs>): Promise<void> => {
await smartThingsCommand(argv)

const message = await addPermission(argv.arn, argv.principal, argv.statement)
console.log(message)
}

const cmd: CommandModule<object, CommandArgs> = { command, describe, builder, handler }
export default cmd
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CommandModule } from 'yargs'

import appsCommand from './apps.js'
import appsCreateCommand from './apps/create.js'
import appsAuthorizeCommand from './apps/authorize.js'
import configCommand from './config.js'
import devicepreferencesCommand from './devicepreferences.js'
import devicepreferencesTranslationsCreateCommand from './devicepreferences/translations/create.js'
Expand All @@ -22,6 +23,7 @@ import schemaCreateCommand from './schema/create.js'
export const commands: CommandModule<object, any>[] = [
appsCommand,
appsCreateCommand,
appsAuthorizeCommand,
configCommand,
devicepreferencesCommand,
devicepreferencesTranslationsCreateCommand,
Expand Down

0 comments on commit 6e8e829

Please sign in to comment.