Build and release Azure Functions with Azure DevOps
15 Mar 2019I recently got an Azure Functions version 2.x app up and running in Azure with a build and release pipeline in Azure DevOps and this post is my brain dump of that process.
Create a build pipeline
The first thing I did was to create a new Build pipeline in Azure DevOps. My code was hosted in a repo in DevOps, so I selected the Azure Repos option. I used this template from the Sample ASP.NET Core application for Azure Pipelines docs but did a couple of modifications:
The Microsoft-hosted agent pool provides 6 virtual machine images to choose from, and since my development team is using Visual Studio 2017 I choose the vs2017-win2016
image instead of ubuntu-16.04
.
I added code coverage to the test task:
dotnet test --configuration $(buildConfiguration) --logger trx --collect "Code coverage"
The dotnet publish
task didn’t produce any files, a problem that someone else had noticed in a GitHub issue:
##[warning]Directory 'D:\a\1\a' is empty. Nothing will be added to build artifact 'drop'.
I resolved it by changing the value of the output
parameter from $BUILD_ARTIFACTSTAGINGDIRECTORY
to $(Build.ArtifactStagingDirectory)
:
dotnet publish --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)
The result was a succesfully run build with files published to 'D:\a\1\a'
, then uploaded to a container '#/0000000/drop'
.
Nice! A working build, but I noticed that the task published all of the files instead of a single zip package. I changed that after next step.
Create a release pipeline
Next step was to create a release pipeline. DevOps provides several templates that pre-populate a stage with the appropriate tasks and settings. I chose Deploy a function app to Azure Functions and then some settings needed attention:
Add your artifact from source type Build and then select from the Source dropdown.
For the Deploy Azure App Service task I had to create an Azure service connection for my Azure App Service in Project settings > Pipelines > Service connections.
The task also holds a setting with the file path to the package containing app service contents generated by the build. That settings was defined as:
$(System.DefaultWorkingDirectory)/**/*.zip
And since the files were not zipped as a single package I replaced dotnet publish
with the DotNetCoreCLI@2
task in my build pipeline:
- task: DotNetCoreCLI@2
displayName: Publish
inputs:
command: publish
publishWebProjects: False
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: True
Then my artifact was picked up and succesfully deployed to Azure!
The complete azure-pipelines.yml
looks like this:
trigger:
- master
pool:
vmImage: 'vs2017-win2016'
variables:
buildConfiguration: 'Release'
steps:
- script: |
dotnet build --configuration $(buildConfiguration)
dotnet test --configuration $(buildConfiguration) --logger trx --collect "Code coverage"
failOnStderr: true
- task: DotNetCoreCLI@2
displayName: Publish
inputs:
command: publish
publishWebProjects: False
arguments: '--configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: True
- task: PublishTestResults@2
condition: succeededOrFailed()
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1