Skip to content
This repository was archived by the owner on Jan 15, 2025. It is now read-only.

Commit 782f25c

Browse files
JSprumunozemilio
authored andcommitted
Adding luis:application:create cmd and tests / refactor utils and clo… (#351)
* Adding luis:application:create cmd and tests / refactor utils and clone cmd too * Update create sample code * Remove hardcoded prefix * Move luis flag prefix into shared util file
1 parent b7980c4 commit 782f25c

File tree

5 files changed

+138
-14
lines changed

5 files changed

+138
-14
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*!
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
import {CLIError, Command, flags} from '@microsoft/bf-cli-command'
7+
8+
const utils = require('../../../utils/index')
9+
10+
export default class LuisApplicationCreate extends Command {
11+
static description = 'Creates a new LUIS application'
12+
13+
static examples = [`
14+
$ bf luis:application:create --endpoint {ENDPOINT} --subscriptionKey {SUBSCRIPTION_KEY} --name {NAME} --culture {CULTURE}
15+
--domain {DOMAIN} --description {DESCRIPTION} --initialVersionId {INITIAL_VERSION_ID} --usageScenario {USAGE_SCENARIO}
16+
`]
17+
18+
static flags = {
19+
help: flags.help({char: 'h'}),
20+
endpoint: flags.string({description: 'LUIS endpoint hostname'}),
21+
subscriptionKey: flags.string({description: 'LUIS cognitive services subscription key (aka Ocp-Apim-Subscription-Key)'}),
22+
name: flags.string({description: 'LUIS application name'}),
23+
culture: flags.string({description: 'LUIS application culture'}),
24+
domain: flags.string({description: 'LUIS application domain'}),
25+
description: flags.string({description: 'LUIS application description'}),
26+
initialVersionId: flags.string({description: 'LUIS application initial version Id'}),
27+
usageScenario: flags.string({description: 'LUIS application usage scenario'}),
28+
}
29+
30+
async run() {
31+
const {flags} = this.parse(LuisApplicationCreate)
32+
const flagLabels = Object.keys(LuisApplicationCreate.flags)
33+
const configDir = this.config.configDir
34+
35+
const {
36+
endpoint,
37+
subscriptionKey,
38+
name,
39+
culture,
40+
domain,
41+
description,
42+
initialVersionId,
43+
usageScenario
44+
} = await utils.processInputs(flags, flagLabels, configDir)
45+
46+
const requiredProps = {endpoint, subscriptionKey, name, domain}
47+
utils.validateRequiredProps(requiredProps)
48+
49+
const client = utils.getLUISClient(subscriptionKey, endpoint)
50+
const options = {}
51+
52+
const applicationCreateObject = {name, culture, domain, description, initialVersionId, usageScenario}
53+
54+
try {
55+
const newAppId = await client.apps.add(applicationCreateObject, options)
56+
this.log(`App successfully created with id ${newAppId}.`)
57+
} catch (err) {
58+
throw new CLIError(`Failed to create app: ${err}`)
59+
}
60+
}
61+
}

packages/luis/src/commands/luis/version/clone.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ export default class LuisVersionClone extends Command {
2525

2626
async run() {
2727
const {flags} = this.parse(LuisVersionClone)
28+
const flagLabels = Object.keys(LuisVersionClone.flags)
2829
const configDir = this.config.configDir
29-
const configPrefix = 'luis__'
3030

31-
const {appId, endpoint, subscriptionKey, versionId, targetVersionId} = await utils.processInputs(flags, configDir, configPrefix)
31+
const {appId, endpoint, subscriptionKey, versionId, targetVersionId} = await utils.processInputs(flags, flagLabels, configDir)
3232

3333
const requiredProps = {appId, endpoint, subscriptionKey, versionId, targetVersionId}
3434
utils.validateRequiredProps(requiredProps)

packages/luis/src/utils/index.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,17 @@ const getPropFromConfig = async (prop: string, configDir: string) => {
4343
}
4444
}
4545

46-
const processInputs = async (flags: any, configDir: string, prefix: string) => {
46+
const processInputs = async (flags: any, flagLabels: string[], configDir: string) => {
47+
const configPrefix = 'luis__'
4748
let config = await getUserConfig(configDir)
48-
config = config ? filterConfig(config, prefix) : config
49-
const input = {
50-
appId: flags.appId || (config ? config.luis__appId : null),
51-
endpoint: flags.endpoint || (config ? config.luis__endpoint : null),
52-
subscriptionKey: flags.subscriptionKey || (config ? config.luis__subscriptionKey : null),
53-
versionId: flags.versionId || (config ? config.luis__versionId : null),
54-
targetVersionId: flags.targetVersionId || (config ? config.luis__targetVersionId : null)
55-
}
49+
config = config ? filterConfig(config, configPrefix) : config
50+
const input: any = {}
51+
flagLabels
52+
.filter(flag => flag !== 'help')
53+
.map((flag: string) => {
54+
input[flag] = flags[flag] || (config ? config[configPrefix + flag] : null)
55+
})
56+
5657
return input
5758
}
5859

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import {expect, test} from '@oclif/test'
2+
const sinon = require('sinon')
3+
const uuidv1 = require('uuid/v1')
4+
const utils = require('../../../../src/utils/index')
5+
6+
describe('luis:application:create', () => {
7+
8+
before(() => {
9+
const newAppId = uuidv1()
10+
})
11+
12+
beforeEach(() => {
13+
sinon.stub(utils, 'processInputs').returnsArg(0)
14+
})
15+
16+
afterEach(() => {
17+
sinon.restore();
18+
});
19+
20+
test
21+
.stdout()
22+
.command(['luis:application:create', '--help'])
23+
.it('should print the help contents when --help is passed as an argument', ctx => {
24+
expect(ctx.stdout).to.contain('Creates a new LUIS application')
25+
})
26+
27+
test
28+
.stdout()
29+
.stderr()
30+
.command(['luis:application:create', '--endpoint', 'https://westus.api.cognitive.microsoft.com', '--subscriptionKey', uuidv1(), '--culture', 'en-us', '--domain', 'Comics', '--description', 'test description', '--initialVersionId', '0.04', '--usageScenario', 'For use in our test app'])
31+
.it('displays an error if any required input parameters are missing', ctx => {
32+
expect(ctx.stderr).to.contain(`Required input property 'name' missing.`)
33+
})
34+
35+
test
36+
.stdout()
37+
.stderr()
38+
.command(['luis:application:create', '--endpoint', 'https://westus.api.cognitive.microsoft.com', '--name', 'orange_app', '--culture', 'en-us', '--domain', 'Comics', '--description', 'test description', '--initialVersionId', '0.04', '--usageScenario', 'For use in our test app'])
39+
.it('displays an error if any required input parameters are missing', ctx => {
40+
expect(ctx.stderr).to.contain(`Required input property 'subscriptionKey' missing.`)
41+
})
42+
43+
test
44+
.nock('https://westus.api.cognitive.microsoft.com', api => api
45+
.post(uri => uri.includes('apps'))
46+
.reply(201, '99999')
47+
)
48+
.stdout()
49+
.command(['luis:application:create', '--endpoint', 'https://westus.api.cognitive.microsoft.com', '--name', 'orange_app', '--subscriptionKey', uuidv1(), '--culture', 'en-us', '--domain', 'Comics', '--description', 'test description', '--initialVersionId', '0.04', '--usageScenario', 'For use in our test app'])
50+
.it('creates a luis app and returns the new app\'s id', ctx => {
51+
expect(ctx.stdout).to.contain('App successfully created with id 99999')
52+
})
53+
54+
test
55+
.stdout()
56+
.stderr()
57+
.command(['luis:application:create', '--endpoint', 'undefined', '--name', 'orange_app', '--subscriptionKey', uuidv1(), '--culture', 'en-us', '--domain', 'Comics', '--description', 'test description', '--initialVersionId', '0.04', '--usageScenario', 'For use in our test app'])
58+
.it('fails to create an app and displays an error message if the endpoint is null', ctx => {
59+
expect(ctx.stderr).to.contain('Access denied due to invalid subscription key or wrong API endpoint.')
60+
})
61+
62+
})

packages/luis/test/commands/luis/version/clone.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ describe('luis:version:clone', () => {
2323
test
2424
.stdout()
2525
.stderr()
26-
.command(['luis:version:clone', '--versionId', '0.1', '--targetVersionId', '0.2', '--subscriptionKey', uuidv1(), '--endpoint', 'https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/'])
26+
.command(['luis:version:clone', '--versionId', '0.1', '--targetVersionId', '0.2', '--subscriptionKey', uuidv1(), '--endpoint', 'https://westus.api.cognitive.microsoft.com'])
2727
.it('displays an error if any required input parameters are missing', ctx => {
2828
expect(ctx.stderr).to.contain(`Required input property 'appId' missing.`)
2929
})
3030

3131
test
3232
.stdout()
3333
.stderr()
34-
.command(['luis:version:clone', '--appId', uuidv1(), '--versionId', '0.1', '--targetVersionId', '0.2', '--endpoint', 'https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/'])
34+
.command(['luis:version:clone', '--appId', uuidv1(), '--versionId', '0.1', '--targetVersionId', '0.2', '--endpoint', 'https://westus.api.cognitive.microsoft.com'])
3535
.it('displays an error if any required input parameters are missing', ctx => {
3636
expect(ctx.stderr).to.contain(`Required input property 'subscriptionKey' missing.`)
3737
})
@@ -42,7 +42,7 @@ describe('luis:version:clone', () => {
4242
.reply(201, '0.2')
4343
)
4444
.stdout()
45-
.command(['luis:version:clone', '--appId', uuidv1(), '--versionId', '0.1', '--targetVersionId', '0.2', '--subscriptionKey', uuidv1(), '--endpoint', 'https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/'])
45+
.command(['luis:version:clone', '--appId', uuidv1(), '--versionId', '0.1', '--targetVersionId', '0.2', '--subscriptionKey', uuidv1(), '--endpoint', 'https://westus.api.cognitive.microsoft.com'])
4646
.it('clones a luis app and returns the new version number', ctx => {
4747
expect(ctx.stdout).to.contain('App successfully cloned.')
4848
})

0 commit comments

Comments
 (0)