Skip to content

Commit

Permalink
fix: update powershell script to support qna and corsstrain build (#4640
Browse files Browse the repository at this point in the history
)

* update powershell script to support qna and corsstrain

* add more luis details

* fix qna build and lubuild settings, add publishing profile retrieving

* add more readme about publishing profile path param

* add more error handling logic for script

Co-authored-by: Lu Han <32191031+luhan2017@users.noreply.github.com>
  • Loading branch information
Qi Kang and luhan2017 authored Dec 8, 2020
1 parent 99142b6 commit 547f604
Show file tree
Hide file tree
Showing 2 changed files with 189 additions and 42 deletions.
190 changes: 148 additions & 42 deletions runtime/dotnet/azurewebapp/Scripts/deploy.ps1
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
Param(
[string] $name,
[string] $environment,
[string] $hostName,
[string] $luisAuthoringKey,
[string] $luisAuthoringRegion,
[string] $luisEndpointKey,
[string] $qnaSubscriptionKey,
[string] $qnaEndpoint,
[string] $language,
[string] $projFolder = $(Get-Location),
[string] $botPath,
[string] $logFile = $(Join-Path $PSScriptRoot .. "deploy_log.txt")
[string] $publishProfilePath,
[string] $logFile = $(Join-Path $PSScriptRoot .. "deploy_log.txt"),
[string] $runtimeIdentifier = 'win-x64',
[string] $luisResource
)

if ($PSVersionTable.PSVersion.Major -lt 6) {
Expand All @@ -22,6 +29,31 @@ if ((dotnet --version) -lt 3) {
Break
}

# read settings from publishing profile
if ($publishProfilePath) {
Write-Host "Reading publishing profile from : $publishProfilePath ..."
$publishProfile = Get-Content $publishProfilePath | ConvertFrom-Json

Write-Host ($publishProfile | Format-List | Out-String)
$name = $publishProfile.name
$environment = $publishProfile.environment
$hostName = $publishProfile.hostname
$luisResource = $publishProfile.luisResource

#luis configuration
$luisConfig = $publishProfile.settings.luis
$luisAuthoringKey = $luisConfig.authoringKey
$luisEndpointKey = $luisConfig.endpointKey
$luisAuthoringRegion = $luisConfig.region

#qna configuration
$qnaConfig = $publishProfile.settings.qna
$qnaEndpoint = $qnaConfig.endpoint
$qnaSubscriptionKey = $qnaConfig.subscriptionKey

$runtimeIdentifier = $publishProfile.runtimeIdentifier
}

# Get mandatory parameters
if (-not $name) {
$name = Read-Host "? Bot Web App Name"
Expand All @@ -36,6 +68,14 @@ if (-not $language) {
$language = "en-us"
}

if (-not $luisAuthoringKey) {
$luisAuthoringKey = ""
}

if (-not $luisEndpointKey) {
$luisEndpointKey = ""
}

# Reset log file
if (Test-Path $logFile) {
Clear-Content $logFile -Force | Out-Null
Expand All @@ -58,7 +98,15 @@ if (Test-Path $zipPath) {

# Perform dotnet publish step ahead of zipping up
$publishFolder = $(Join-Path $projFolder 'bin\Release\netcoreapp3.1')
dotnet publish -c release -o $publishFolder -v q > $logFile
dotnet publish -c release -o $publishFolder -v q --self-contained true -r $runtimeIdentifier > $logFile

if($?) {
Write-Host "dotnet publish success!"
}
else {
Write-Host "dotnet publish fail!"
break
}

# Copy bot files to running folder
$remoteBotPath = $(Join-Path $publishFolder "ComposerDialogs")
Expand All @@ -77,62 +125,70 @@ Copy-Item -Path (Get-Item -Path $botPath -Exclude ('runtime', 'generated')).Full
$settingsPath = $(Join-Path $remoteBotPath settings appsettings.json)
$settings = Get-Content $settingsPath | ConvertFrom-Json
$luisSettings = $settings.luis
$qnaSettings = $settings.qna

if (-not $luisAuthoringKey) {
$luisAuthoringKey = $luisSettings.authoringKey
}

if (-not $luisAuthoringRegion) {
$luisAuthoringRegion = $luisSettings.region
if (-not $luisAuthoringRegion) {
$luisAuthoringRegion = 'westus'
}
}

# set feature configuration
$featureConfig = @{ }
if ($settings.feature) {
$featureConfig = $settings.feature
}
else {
# Enable all features to true by default
$featureConfig["UseTelementryLoggerMiddleware"] = $true
$featureConfig["UseTranscriptLoggerMiddleware"] = $true
$featureConfig["UseShowTypingMiddleware"] = $true
$featureConfig["UseInspectionMiddleware"] = $true
$featureConfig["UseCosmosDb"] = $true
if (-not $qnaSubscriptionKey) {
$qnaSubscriptionKey = $qnaSettings.subscriptionKey
}

# Add Luis Config to appsettings
if ($luisAuthoringKey -and $luisAuthoringRegion) {
Set-Location -Path $remoteBotPath

$models = Get-ChildItem $remoteBotPath -Recurse -Filter "*.lu" | Resolve-Path -Relative

# Generate Luconfig.json file
$luconfigjson = @{
"name" = $name;
"defaultLanguage" = $language;
"models" = $models
# if luis and qna enabled, crosstrain
if ($luisAuthoringKey -or $qnaSubscriptionKey) {
# if luis or qna enabled, ensure bf cli installed
if (Get-Command bf -errorAction SilentlyContinue) {}
else {
Write-Host "bf command does not exist. Start installation..."
npm i -g @microsoft/botframework-cli@next
bf plugins:install @microsoft/bf-sampler-cli@beta
Write-Host "successfully"
}

$luString = $models | Out-String
Write-Host $luString

$luconfigjson | ConvertTo-Json -Depth 100 | Out-File $(Join-Path $remoteBotPath luconfig.json)
Set-Location -Path $remoteBotPath

# create generated folder if not
if (!(Test-Path generated)) {
$null = New-Item -ItemType Directory -Force -Path generated
}
if (!(Test-Path generated\interruption)) {
$null = New-Item -ItemType Directory -Force -Path generated\interruption
}

# ensure bot cli is installed
if (Get-Command bf -errorAction SilentlyContinue) {}
bf luis:cross-train --in . --out generated\interruption --config .\settings\cross-train.config.json --force

if ($luisAuthoringKey) {
bf sampler:sampling --in generated\interruption --out generated\interruption --force
}

if($?) {
Write-Host "bf luis:cross-train, sampler:sampling success!"
}
else {
Write-Host "bf luis:build does not exist. Start installation..."
npm i -g @microsoft/botframework-cli
Write-Host "successfully"
Write-Host "bf luis:cross-train, sampler:sampling fail!"
break
}
}

# if luis enabled
if ($luisAuthoringKey) {
Set-Location -Path $remoteBotPath

$files = Get-ChildItem -Path generated\interruption
if ($files.Count -eq 0) {
Write-Host 'Warning: have luis authoring key but lubuild input is empty!'
}

# Execute bf luis:build command
bf luis:build --luConfig $(Join-Path $remoteBotPath luconfig.json) --botName $name --authoringKey $luisAuthoringKey --dialog crosstrained --out ./generated --suffix $environment -f --region $luisAuthoringRegion
# execute lubuild
bf luis:build --in generated\interruption --authoringKey $luisAuthoringKey --botName $name --out generated --suffix $environment --force --log --defaultCulture $language

if ($?) {
Write-Host "lubuild succeeded"
Expand All @@ -144,10 +200,10 @@ if ($luisAuthoringKey -and $luisAuthoringRegion) {

Set-Location -Path $projFolder

$settings = New-Object PSObject

# get all luis settings
$luisConfigFiles = Get-ChildItem -Path $publishFolder -Include "luis.settings*" -Recurse -Force

# get all luis app ids
$luisAppIds = @{ }

foreach ($luisConfigFile in $luisConfigFiles) {
Expand All @@ -161,9 +217,17 @@ if ($luisAuthoringKey -and $luisAuthoringRegion) {
$luisConfig = @{ }

$luisConfig["endpoint"] = $luisEndpoint
$luisConfig["authoringKey"] = $luisAuthoringKey
$luisConfig["authoringEndpoint"] = $luisEndpointKey
$luisConfig["authoringRegion"] = $luisAuthoringRegion
$luisConfig["defaultLanguage"] = $language
$luisConfig["environment"] = $environment
$luisConfig["region"] = $luisAuthoringRegion
$luisConfig["endpointKey"] = $luisEndpointKey

foreach ($key in $luisAppIds.Keys) { $luisConfig[$key] = $luisAppIds[$key] }

# add luis settings to the main settings
$settings | Add-Member -Type NoteProperty -Force -Name 'luis' -Value $luisConfig

$tokenResponse = (az account get-access-token) | ConvertFrom-Json
Expand All @@ -174,14 +238,18 @@ if ($luisAuthoringKey -and $luisAuthoringRegion) {
Break
}

# assign luis key to luis app ids, firstly get luis account by $name-$environment-luis
Write-Host "Getting Luis accounts..."
$luisAccountEndpoint = "$luisEndpoint/luis/api/v2.0/azureaccounts"
$luisAccount = $null
try {
if (-not $luisResource) {
$luisResource = "$name-$environment-luis"
}
$luisAccounts = Invoke-WebRequest -Method GET -Uri $luisAccountEndpoint -Headers @{"Authorization" = "Bearer $token"; "Ocp-Apim-Subscription-Key" = $luisAuthoringKey } | ConvertFrom-Json

foreach ($account in $luisAccounts) {
if ($account.AccountName -eq "$name-$environment-luis") {
if ($account.AccountName -eq $luisResource) {
$luisAccount = $account
break
}
Expand All @@ -192,11 +260,16 @@ if ($luisAuthoringKey -and $luisAuthoringRegion) {
break
}

if (-not $luisAccount) {
Write-Host "Could not find your luis account which matches '$name-$environment-luis', please check your command or specify 'luisResource' parameter."
break
}

$luisAccountBody = $luisAccount | ConvertTo-Json

# Assign each luis id in luisAppIds with the endpoint key
foreach ($k in $luisAppIds.Keys) {
$luisAppId = $luisAppIds.Item($k)
$luisAppId = $luisAppIds.Item($k).appId
Write-Host "Assigning to Luis app id: $luisAppId"
$luisAssignEndpoint = "$luisEndpoint/luis/api/v2.0/apps/$luisAppId/azureaccounts"
try {
Expand All @@ -210,20 +283,53 @@ if ($luisAuthoringKey -and $luisAuthoringRegion) {
}
}

$settings | Add-Member -Type NoteProperty -Force -Name 'feature' -Value $featureConfig
# if qna enabled
if ($qnaSubscriptionKey) {
Set-Location -Path $remoteBotPath

$files = Get-ChildItem -Path generated\interruption
if ($files.Count -eq 0) {
Write-Host 'Warning: have qna subscription key but qna build input is empty!'
}


bf qnamaker:build --in generated\interruption --subscriptionKey $qnaSubscriptionKey --botName $name --out generated --suffix $environment --force --log --defaultCulture $language
if ($?) {
Write-Host "qna build succeeded"
}
else {
Write-Host "qna build failed, please verify your qna models."
Break
}

$qnaConfig = @{ }

$qnaConfig["endpoint"] = $qnaEndpoint
$qnaConfig["subscriptionKey"] = $qnaSubscriptionKey
$settings | Add-Member -Type NoteProperty -Force -Name 'qna' -Value $qnaConfig
}


# write settings file to settings path
$settings | ConvertTo-Json -depth 100 | Out-File $settingsPath

$resourceGroup = "$name-$environment"

# if all done, compress the folder and deploy to azure
if ($?) {
# Compress source code
Get-ChildItem -Path "$($publishFolder)" | Compress-Archive -DestinationPath "$($zipPath)" -Force | Out-Null

# Publish zip to Azure
Write-Host "> Publishing to Azure ..." -ForegroundColor Green

if (-not $hostName) {
$hostName = "$name-$environment"
}

$deployment = (az webapp deployment source config-zip `
--resource-group $resourceGroup `
--name "$name-$environment" `
--name $hostName `
--src $zipPath `
--output json) 2>> $logFile

Expand Down
41 changes: 41 additions & 0 deletions runtime/dotnet/azurewebapp/Scripts/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# How to use deploy.ps1 to publish your bot to azure

Ensure you have installed necessary dependencies:
* azure cli (latest version)
* dotnet core (version >= 3.0)
* powershell (version >= 6.0)
* bf command (npm i -g @microsoft/botframework-cli@next)
* bf plugins (bf plugins:install @microsoft/bf-sampler-cli@beta)

Then please refer to the following steps:

1. Eject your own C# runtime in composer
2. Navigate to your runtime azurewebapp folder, for example C:\user\test\ToDoBot\runtime\azurewebapp
3. Execute this command under azurewebapp folder:
```
\Scripts\deploy.ps1 -name <name of resource group> -hostName <hostname of azure webapp> -luisAuthoringKey <luis authoring key> -qnaSubscriptionKey <qna subscription key> -environment <environment >
```
4. Or if you have saved your publishing profile to json format (profile.json), you can execute:
```
\Scripts\deploy.ps1 -publishProfilePath < path to your publishing profile>
```
parameters of deploy.ps1:
| Param | |
| ------------- |:-------------:|
| name | name of your Bot Channels Registration|
| environment | environment, same as composer |
| hostName | hostname of your azure webapp instance |
| luisAuthoringKey | luis authoring key, only needed in luis|
| luisAuthoringRegion | luis authoring region, could be optional|
| qnaSubscriptionKey | qna subscription key, only needed in qna feature|
| language | language of yoru qna & luis, defaults to 'en-us' |
| botPath | path to your bot assests, defaults to ../../ for ejected runtime |
| logFile | path to save your log file, deafults to deploy_log.txt |
| runtimeIdentifier | runtime identifier of your C# publishing targets, defaults to win-x64, please refer to this doc: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog|
| luisResource | the name of your luis prediction (not authoring) resource |
| publishProfilePath | the path to your publishing profile (json formate) |

0 comments on commit 547f604

Please sign in to comment.