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

Commit 294689d

Browse files
JSprumunozemilio
authored andcommitted
Create bf luis plugin commands (#337)
* bf-luis-cli plugin initial commit * Adding clone cmd * Deleting files * Get values from config if not present in flags * Add unit tests with HTTP mock * Lint fixes * Update readme * Move endpoint monkey patch into shared utils file so we only have to remove it once later * Convert utils filte to TS, lint fixes, read config dir refactor * Regenerate readme * Eliminate redundant var * Lint fix * Remove duplicate content from readme * Update readme * Remove outer try catch
1 parent a130cb9 commit 294689d

File tree

7 files changed

+170
-76
lines changed

7 files changed

+170
-76
lines changed

packages/luis/README.md

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,41 +12,27 @@
1212
* [Usage](#usage)
1313
* [Commands](#commands)
1414
<!-- tocstop -->
15-
# Usage
16-
<!-- usage -->
17-
```sh-session
18-
$ npm install -g @microsoft/bf-luis-cli
19-
$ oclif-example COMMAND
20-
running command...
21-
$ oclif-example (-v|--version|version)
22-
@microsoft/bf-luis-cli/0.0.0 win32-x64 node-v10.16.3
23-
$ oclif-example --help [COMMAND]
24-
USAGE
25-
$ oclif-example COMMAND
26-
...
27-
```
28-
<!-- usagestop -->
15+
2916
# Commands
3017
<!-- commands -->
31-
* [`oclif-example hello [FILE]`](#oclif-example-hello-file)
18+
* [`bf luis:version:clone`](#bf-luisversionclone)
3219

33-
## `oclif-example hello [FILE]`
20+
## `bf luis:version:clone`
3421

35-
describe the command here
22+
Creates a new version equivalent to the current snapshot of the selected application version.
3623

3724
```
3825
USAGE
39-
$ oclif-example hello [FILE]
26+
$ bf luis:version:clone --appId {APP_ID} --versionId {VERSION_ID} --targetVersionId {TARGET_VERSION_ID} --endpoint {ENDPOINT} --subscriptionKey {SUBSCRIPTION_KEY}
4027
4128
OPTIONS
42-
-f, --force
43-
-h, --help show CLI help
44-
-n, --name=name name to print
45-
46-
EXAMPLE
47-
$ oclif-example hello
48-
hello world from ./src/hello.ts!
29+
-h, --help show CLI help
30+
--appId LUIS application Id
31+
--versionId LUIS version Id
32+
--targetVersionId LUIS target version Id
33+
--endpoint LUIS endpoint hostname
34+
--subscriptionKey LUIS cognitive services subscription key (aka Ocp-Apim-Subscription-Key)
4935
```
5036

51-
_See code: [src\commands\hello.ts](https://github.com/packages/bf-luis-cli/blob/v0.0.0/src\commands\hello.ts)_
37+
_See code: [src\commands\luis\version\clone.ts](https://github.com/microsoft/botframework-cli/tree/master/packages/luis/src/commands/luis/version/clone/index.ts)_
5238
<!-- commandsstop -->

packages/luis/package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
"version": "0.0.0",
44
"bugs": "https://github.com/packages/bf-luis-cli/issues",
55
"dependencies": {
6+
"@microsoft/bf-cli-command": "1.0.0",
67
"@oclif/command": "^1.5.19",
78
"@oclif/config": "^1.13.3",
9+
"@types/sinon": "^7.5.0",
810
"azure-cognitiveservices-luis-authoring": "2.1.1",
11+
"fs-extra": "^8.1.0",
912
"ms-rest": "2.5.3",
1013
"tslib": "^1.10.0"
1114
},
@@ -22,9 +25,11 @@
2225
"mocha": "^5.2.0",
2326
"nyc": "^14.1.1",
2427
"rimraf": "^3.0.0",
28+
"sinon": "^7.5.0",
2529
"ts-node": "^8.4.1",
2630
"tslint": "^5.20.1",
27-
"typescript": "^3.7.2"
31+
"typescript": "^3.7.2",
32+
"uuid": "^3.3.3"
2833
},
2934
"engines": {
3035
"node": ">=8.0.0"
@@ -42,7 +47,7 @@
4247
"license": "MIT",
4348
"oclif": {
4449
"commands": "./lib/commands",
45-
"bin": "oclif-example",
50+
"bin": "bf",
4651
"devPlugins": [
4752
"@oclif/plugin-help"
4853
]

packages/luis/src/commands/hello.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 LuisVersionClone extends Command {
11+
static description = 'Creates a new version equivalent to the current snapshot of the selected application version.'
12+
13+
static examples = [`
14+
$ bf luis:version:clone --appId {APP_ID} --versionId {VERSION_ID} --targetVersionId {TARGET_VERSION_ID} --endpoint {ENDPOINT} --subscriptionKey {SUBSCRIPTION_KEY}
15+
`]
16+
17+
static flags = {
18+
help: flags.help({char: 'h'}),
19+
appId: flags.string({description: 'LUIS application Id'}),
20+
versionId: flags.string({description: 'LUIS version Id'}),
21+
targetVersionId: flags.string({description: 'LUIS target version Id'}),
22+
endpoint: flags.string({description: 'LUIS endpoint hostname'}),
23+
subscriptionKey: flags.string({description: 'LUIS cognitive services subscription key (aka Ocp-Apim-Subscription-Key)'}),
24+
}
25+
26+
async run() {
27+
const {flags} = this.parse(LuisVersionClone)
28+
const configDir = this.config.configDir
29+
30+
const appId = flags.appId || await utils.getPropFromConfig('appId', configDir)
31+
const endpoint = flags.endpoint || await utils.getPropFromConfig('endpoint', configDir)
32+
const subscriptionKey = flags.subscriptionKey || await utils.getPropFromConfig('subscriptionKey', configDir)
33+
const versionId = flags.versionId || await utils.getPropFromConfig('versionId', configDir)
34+
const targetVersionId = flags.targetVersionId || await utils.getPropFromConfig('targetVersionId', configDir)
35+
36+
const requiredProps = {appId, endpoint, subscriptionKey, versionId, targetVersionId}
37+
utils.validateRequiredProps(requiredProps)
38+
39+
const client = utils.getLUISClient(subscriptionKey, endpoint)
40+
const options = {
41+
versionCloneObject: {
42+
version: targetVersionId
43+
}
44+
}
45+
46+
try {
47+
const latestVersion = await client.versions.clone(appId, versionId, options)
48+
this.log(`App successfully cloned. Latest version is now: ${latestVersion}`)
49+
} catch (err) {
50+
throw new CLIError(`Failed to clone app: ${err}`)
51+
}
52+
}
53+
}

packages/luis/src/utils/index.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
/*!
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License.
5+
*/
6+
7+
import {CLIError} from '@microsoft/bf-cli-command'
8+
const path = require('path')
9+
const fs = require('fs-extra')
10+
const msRest = require('ms-rest')
11+
const {LUISAuthoringClient} = require('azure-cognitiveservices-luis-authoring')
12+
13+
const getUserConfig = async (configPath: string) => {
14+
if (fs.existsSync(path.join(configPath, 'config.json'))) {
15+
return fs.readJSON(path.join(configPath, 'config.json'), {throws: false})
16+
}
17+
}
18+
19+
const getLUISClient = (subscriptionKey: string, endpoint: string) => {
20+
const token = {
21+
inHeader: {
22+
'Ocp-Apim-Subscription-Key': subscriptionKey
23+
}
24+
}
25+
const creds = new msRest.ApiKeyCredentials(token)
26+
const luisClient = new LUISAuthoringClient(creds, endpoint)
27+
luisClient.baseUri = 'https://westus.api.cognitive.microsoft.com/luis/authoring/v3.0-preview/'
28+
return luisClient
29+
}
30+
31+
const getPropFromConfig = async (prop: string, configDir: string) => {
32+
const config = await getUserConfig(configDir)
33+
if (config && config[prop]) {
34+
return config[prop]
35+
}
36+
}
37+
38+
const validateRequiredProps = (configObj: any) => {
39+
Object.keys(configObj).forEach(key => {
40+
if (!configObj[key]) {
41+
throw new CLIError(`Required input property '${key}' missing. Please pass it in as a flag or set it in the config file.`)
42+
}
43+
})
44+
}
45+
46+
module.exports.getLUISClient = getLUISClient
47+
module.exports.getPropFromConfig = getPropFromConfig
48+
module.exports.validateRequiredProps = validateRequiredProps

packages/luis/test/commands/hello.test.ts

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
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:version:clone', () => {
7+
8+
beforeEach(() => {
9+
sinon.stub(utils, 'getPropFromConfig').callsFake(() => null)
10+
})
11+
12+
afterEach(() => {
13+
sinon.restore();
14+
});
15+
16+
test
17+
.stdout()
18+
.command(['luis:version:clone', '--help'])
19+
.it('should print the help contents when --help is passed as an argument', ctx => {
20+
expect(ctx.stdout).to.contain('Creates a new version equivalent to the current snapshot of the selected application version.')
21+
})
22+
23+
test
24+
.stdout()
25+
.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/'])
27+
.it('displays an error if any required input parameters are missing', ctx => {
28+
expect(ctx.stderr).to.contain(`Required input property 'appId' missing.`)
29+
})
30+
31+
test
32+
.stdout()
33+
.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/'])
35+
.it('displays an error if any required input parameters are missing', ctx => {
36+
expect(ctx.stderr).to.contain(`Required input property 'subscriptionKey' missing.`)
37+
})
38+
39+
test
40+
.nock('https://westus.api.cognitive.microsoft.com', api => api
41+
.post(uri => uri.includes('clone'))
42+
.reply(201, '0.2')
43+
)
44+
.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/'])
46+
.it('clones a luis app and returns the new version number', ctx => {
47+
expect(ctx.stdout).to.contain('App successfully cloned.')
48+
})
49+
50+
})

0 commit comments

Comments
 (0)