Create Bot for Microsoft Graph with DevOps 6: Continuous Deployment - Release Definition
This time, I create a Release Definition to complete the CI/CD pipeline. While build definition defines how to build the source, release definition defines how to release the compiled bits. I include following three tasks.
- Infrastructure as a Code (ARM template for Azure) to automate infrastructure.
- Release
- Function Test
You can find the detail of ARM Template here.
ARM (Azure Resource Manager) Template
I already created App Service via Visual Studio, but I will automate it by using ARM Template.
Get Template
It’s tedious to write a template from scratch, and you can get it from Azure Portal.
1. Login to https://portal.azure.com. To start from scratch, let’s delete the resource group provisioned previously.
* Before delete the environment, please take a note for each application settings as you need them later.
2. Next, create a Web App from new.
3. Specify the settings and click [Automation options], which generates templates for you.
4. Click [Download]
5. Extract the template.zip file. You find template.json, which contains service definitions and parameters.json, which contains values for each parameters.
6. As this template only contains single WebApp service definition, you can add more as you need. For now, replace the template.json as follows.
{
"parameters": {
"webName": {
"type": "string"
},
"webNameTest": {
"type": "string"
},
"hostingPlanName": {
"type": "string"
},
"hostingEnvironment": {
"type": "string"
},
"location": {
"type": "string"
},
"sku": {
"type": "string"
},
"skuCode": {
"type": "string"
},
"workerSize": {
"type": "string"
},
"serverFarmResourceGroup": {
"type": "string"
},
"subscriptionId": {
"type": "string"
},
"botId": {
"type": "string"
},
"microsoftAppId": {
"type": "string"
},
"microsoftAppPassword": {
"type": "string"
},
"activeDirectory.RedirectUrl": {
"type": "string"
},
"botIdTest": {
"type": "string"
},
"microsoftAppIdTest": {
"type": "string"
},
"microsoftAppPasswordTest": {
"type": "string"
},
"activeDirectory.RedirectUrlTest": {
"type": "string"
}
},
"resources": [
{
"apiVersion": "2016-03-01",
"name": "[parameters('webName')]",
"type": "Microsoft.Web/sites",
"properties": {
"name": "[parameters('webName')]",
"serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
"hostingEnvironment": "[parameters('hostingEnvironment')]"
},
"location": "[parameters('location')]",
"tags": {
"[concat('hidden-related:', '/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "empty"
},
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"resources": [
{
"apiVersion": "2015-08-01",
"name": "appsettings",
"type": "config",
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"BotId": "[parameters('botId')]",
"MicrosoftAppId": "[parameters('microsoftAppId')]",
"MicrosoftAppPassword": "[parameters('microsoftAppPassword')]",
"ActiveDirectory.RedirectUrl": "[parameters('activeDirectory.RedirectUrl')]"
},
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('webName'))]"
]
}
]
},
{
"apiVersion": "2016-03-01",
"name": "[parameters('webNameTest')]",
"type": "Microsoft.Web/sites",
"properties": {
"name": "[parameters('webNameTest')]",
"serverFarmId": "[concat('/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]",
"hostingEnvironment": "[parameters('hostingEnvironment')]"
},
"location": "[parameters('location')]",
"tags": {
"[concat('hidden-related:', '/subscriptions/', parameters('subscriptionId'),'/resourcegroups/', parameters('serverFarmResourceGroup'), '/providers/Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]": "empty"
},
"dependsOn": [
"[concat('Microsoft.Web/serverfarms/', parameters('hostingPlanName'))]"
],
"resources": [
{
"apiVersion": "2015-08-01",
"name": "appsettings",
"type": "config",
"tags": {
"displayName": "WebAppSettings"
},
"properties": {
"BotId": "[parameters('botIdTest')]",
"MicrosoftAppId": "[parameters('microsoftAppIdTest')]",
"MicrosoftAppPassword": "[parameters('microsoftAppPasswordTest')]",
"ActiveDirectory.RedirectUrl": "[parameters('activeDirectory.RedirectUrlTest')]"
},
"dependsOn": [
"[concat('Microsoft.Web/sites/', parameters('webNameTest'))]"
]
}
]
},
{
"apiVersion": "2016-09-01",
"name": "[parameters('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('location')]",
"properties": {
"name": "[parameters('hostingPlanName')]",
"workerSizeId": "[parameters('workerSize')]",
"numberOfWorkers": "1",
"hostingEnvironment": "[parameters('hostingEnvironment')]"
},
"sku": {
"Tier": "[parameters('sku')]",
"Name": "[parameters('skuCode')]"
}
}
],
"$schema": "https://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json#",
"contentVersion": "1.0.0.0"
}
7. Replace the code in paramters.json. Change the value to fit your environment.
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"webName": {
"value": "o365botprod"
},
"webNameTest": {
"value": "o365bottest"
},
"hostingPlanName": {
"value": "O365BotPlan"
},
"hostingEnvironment": {
"value": ""
},
"location": {
"value": "South Central US"
},
"sku": {
"value": "Standard"
},
"workerSize": {
"value": "0"
},
"serverFarmResourceGroup": {
"value": "O365BotRG"
},
"skuCode": {
"value": "S1"
},
"subscriptionId": {
"value": "__YourAsureSubscriptionId__"
},
"botId": {
"value": "__YourBotId__"
},
"microsoftAppId": {
"value": "__YourMicrosoftAppId__"
},
"microsoftAppPassword": {
"value": "__YourMicrosoftAppPassword__"
},
"activeDirectory.RedirectUrl": {
"value": "__YourSite__/api/OAuthCallback"
},
"botIdTest": {
"value": "__YourTestBotId__"
},
"microsoftAppIdTest": {
"value": "__YourTestMicrosoftAppId__"
},
"microsoftAppPasswordTest": {
"value": "__YourTestMicrosoftAppPassword__"
},
"activeDirectory.RedirectUrlTest": {
"value": "__YourTestSite__/api/OAuthCallback"
}
}
}
Create repository for ARM template
In VSTS, create new repository for ARM template.
1. Login to your VSTS and go to the project.
2. Create the repository dropdown and click [New repository].
3. Enter any name such as ARM.
4. Click [Initialize].
5. Once the repository created, copy template.json and parameters.json.
Release Definition
Now I am ready to create the Release Definition.
Create Release Definitoin
1. Select Build & Release and go to Releases, click [New definition].
2. Select Empty as template and click [Next].
3. Select your build for this release and enable [Continuous deployment]. As you can see, Jenkins is also supported .
Now blank definition is created.
Add Artifacts
If you need files in addition to Build output, you can link them as Artifact.
1. Select Artifacts tab and click [Link an artifact source]
2. Select ARM repository by using Git type.
3. Do the same for BotWithDevOps Repository.
Add ARM task
1. Go back to Environment tab, and rename [Environment 1] to [ARM]
2. Click [Add tasks].
3. From Deploy category, add [Azure Resource Group Deployment].
4. Change the template version down to [1.*]. v2 didn’t work well in my lab.
5.Select the Azure subscription, and click [Authorize]. Select [Create or update resource group] for Action which create the environment if not exist, otherwise update the settings to match with templates.
6. Click […] menu next to Template, and select template.json from ARM artifact.
7. Do the same for parameters.json.
Add Release Definition
1. Click [Add environment] and select [Create new environment].
2. Select [Azure App Service Deployment with Test] template.
3. Select [Automatically approve] and create.
4. Change the environment name to Test.
5. Specify Azure Subscription and App Service Name.
6. Select RunTests task, and update Test assemblies to *functiontests*.dll.
7. Click […] for Settings File
8. Select Test.runsettings from BotWithDevOps git.
9. I also enabled [Code coverage enabled]. Just select any option as you want.
10. Click [Run on agent] and select [Hosted VS2017].
11. Let’s add prod environment, too. You can clone the environment this time.
12. Change the environment name to [Prod]
13. Change App Service name.
14. Update Run Tests Settings file, too.
15. Then name the release definition and click [Save]
Test the Release Definition
Let’s test the definition.
1. Click [Create Release] from Release.
2. Select the latest check-in and create.
3. Select the definition on the left pane, and you see release is queued. Click […] to open it.
4. Click Log tab to see details.
5. Confirm the result. If something went wrong, fix the issue.
Summery
Okay, most of the DevOps part has been done! I will start introducing BotBuilder feature from next time.
Ken