VSTS - YAML Build Definitions
2017-11-28
Using YAML to define your builds
In a previous post I talked about high-level and somewhat generic approaches to getting your CICD pipeline to be responsible for more than just your builds but also you infrastructure deployment.
Now I'd like to walk though a an actual implementation of a build definition as code using a ASP.NET Core application being built on VSTS.
Here is a quick little slug of PowerShell to get a local repo started
$sourceDirectory = "src"
$solutionName = "Solution01"
$appName = "WebApp01"
# Get the default .gitignore from GitHub
Invoke-WebRequest -UseBasicParsing `
-Uri https://raw.githubusercontent.com/github/gitignore/master/VisualStudio.gitignore | `
Select-Object -ExpandProperty Content | `
Out-File .gitignore -Encoding Ascii
#Create a mvc & test project and wire them up to a solution file
dotnet new mvc -o ".\$sourceDirectory\$appName" -n "$appName"
dotnet new xunit -o ".\$sourceDirectory\$appName.Tests" -n "$appName.Tests"
dotnet add ".\$sourceDirectory\$appName.Tests\$appName.Tests.csproj" reference ".\$sourceDirectory\$appName\$appName.csproj"
dotnet new sln -o .\$sourceDirectory\ -n "$solutionName"
dotnet sln ".\$sourceDirectory\$solutionName.sln" add ".\$sourceDirectory\$appName\$appName.csproj"
dotnet sln ".\$sourceDirectory\$solutionName.sln" add ".\$sourceDirectory\$appName.Tests\$appName.Tests.csproj"
# Create a git repo
git init
git add -A
git commit -m "Adds sample application and tests"
# Verify the tests pass
dotnet test ".\$sourceDirectory\$appName.Tests\"
Now that you have a sample project to test with go create a VSTS project for you to build and ultimately deploy with. Once you have a project created push your repo to that projects repository.
Let's get started with some positional significant YAML
Add a file named .vsts-ci.yml
to the root of your repo and push it to your remote.
steps:
- powershell: Write-Host "This agent is running PowerShell v$($PSVersionTable.PSVersion.Major)"
displayName: PowerShell Version Report Script
In your build log you should see something similar in the PowerShell Version Report Script
Outputting the agent's version of PowerShell is not all that interesting. Let's turn our attention to the sample project we built earlier. Let's get a restore and build command added to our build task list for the default phase.
steps:
- task: dotNetCoreCLI@1
displayName: dotnet restore
inputs:
command: restore
projects: "**/*.csproj"
- task: dotNetCoreCLI@1
displayName: dotnet build
inputs:
command: build
projects: "src/Solution01.sln"
arguments: --configuration Release
These steps are using two dotnet core cli tasks to call dotnet restore
against all of our csproj files and dotnet build
against our solution file for a release configuration so we can get to a "build once and configure everywhere else" state.
The results are happy little green checkmarks - we like these.
Our build summary is showing that two extra steps, dotnet restore and dotnet build showed up for our new addition to our .vsts-ci.yml
file
As part of our sample bootstrap script we also added a sample, albeit, useless test (that isn't even an Assert.True(true)) but it still passes. Let's add that task to your YAML file.
steps:
- task: dotNetCoreCLI@1
displayName: dotnet restore
inputs:
command: restore
projects: "**/*.csproj"
- task: dotNetCoreCLI@1
displayName: dotnet build
inputs:
command: build
projects: "src/Solution01.sln"
arguments: --configuration Release
- task: dotNetCoreCLI@1
displayName: dotnet test
inputs:
command: test
projects: "**/*Tests/*.csproj"
arguments: --configuration Release --logger "trx;LogFileName=$(Agent.TempDirectory)\\Results.trx" --no-build
In our steps section we added the dotnet test
task command which will wildcard down through the src
directory and looking for project directories with Tests
in the directory path. Again using a Release configuration and a --no-build
flag so that we are preserving our binaries from our build step. We are also instructing the rest running to publish the test results to a temp directory in the well-known xml based trx file format.
Now our build summary is showing an extra step of dotnet test appeared as a result of adding to the .vsts-ci.yml
file.
Let's keep pressing forward. Test are fine to run but you need to have a report aggregator pick them up so we get the pass fail status of the build as they related to the tests and for historical context of our tests for the project.
steps:
- task: dotNetCoreCLI@1
displayName: dotnet restore
inputs:
command: restore
projects: "**/*.csproj"
- task: dotNetCoreCLI@1
displayName: dotnet build
inputs:
command: build
projects: "src/Solution01.sln"
arguments: --configuration Release
- task: dotNetCoreCLI@1
displayName: dotnet test
inputs:
command: test
projects: "**/*Tests/*.csproj"
arguments: --configuration Release --logger "trx;LogFileName=$(Agent.TempDirectory)\\Results.trx" --no-build
- task: PublishTestResults@1
displayName: Publish Test Results
inputs:
testRunner: VSTest
testResultsFiles: "$(Agent.TempDirectory)\\*.trx"
VSTS can pickup our unit test runners test results so that we can report directly against them on the current build but also to for build history.
More checkmarks appearing this time for our Publish Test Results item in the list.
The last couple of steps to add are to run dotnet publish
and to add the VSTS publish task so that the artifacts are available further down the pipeline.
steps:
- task: dotNetCoreCLI@1
displayName: dotnet restore
inputs:
command: restore
projects: "**/*.csproj"
- task: dotNetCoreCLI@1
displayName: dotnet build
inputs:
command: build
projects: "src/Solution01.sln"
arguments: --configuration Release
- task: dotNetCoreCLI@1
displayName: dotnet test
inputs:
command: test
projects: "**/*Tests/*.csproj"
arguments: --configuration Release --logger "trx;LogFileName=$(Agent.TempDirectory)\\Results.trx" --no-build
- task: PublishTestResults@1
displayName: Publish Test Results
inputs:
testRunner: VSTest
testResultsFiles: "$(Agent.TempDirectory)\\*.trx"
- task: dotNetCoreCLI@1
displayName: dotnet publish
inputs:
command: publish
arguments: --configuration Release --output $(Build.ArtifactStagingDirectory)
zipAfterPublish: true
- task: publishBuildArtifacts@1
displayName: Publish Artifacts
inputs:
PathtoPublish: $(Build.ArtifactStagingDirectory)
ArtifactName: drop
ArtifactType: Container
Add the similarly named items of dotnet publish and Publish Artifacts to the .vsts-ci.yml
file we can see where the dotnet cli is collecting all the files needed to create the ASP.NET Core application into a specific directly and handing that off to the VSTS task of 'sharing' the designated directory so that the contents are available further downstream.
With this final change we can see a partially complete CI pipeline here that goes through the a dotnet restore, dotnet build, dotnet test, Publish Test Results, dotnet publish and Publishing Artifacts. The missing part that we haven't added it deploying our infrastructure that would be used for solely for the CI process for integration tests. This would be in the form of the Deploy Resource Groups task. We will touch on that in the next post.
Hopefully as this feature matures out of preview we'll see a way to visualize what that these code based pipelines look like in VSTS. Developer time validation / linting component is going to be a necessary as the rinse repeat workflow of changing an item, committing and pushing it rather time consuming. I could also imagine features that would work hand in hand with the dotnet templating cli so that as you bring in projects to your solution your YAML build script is created or updated accordingly.