Showing posts with label TFS. Show all posts
Showing posts with label TFS. Show all posts

Thursday, June 7, 2018

My new course : Continuous Delivery with Visual Studio Team Services published


Over the last 3 months I was busy working on my course on Continuous Delivery with Visual Studio Team Services

The course is published by Packt - a leading UK provider of Technology eBooks, Videos and Blogs, and their editors and marketing department has done a fantastic job of helping me with with creative graphics and animations to bring life to this course.


This course is intended for software development professionals who want to learn about Continuous Delivery in a technical value stream as supported by Visual Studio Team Services in order to continually deliver working software at scale. You'll learn how to create, build, test and release a containerized ASP.NET web api to kubernetes cluster on Azure.


The course consists out of seven sections:
  • Introduction to continuous delivery - We'll learn about Continuous Delivery, the business goals and principles of Continuous Delivery
  • Introduction to visual studio team services - We'll learn about the different elements of Visual Studio Team Services and how they function and how using these connected tools you can move your organization to a full-fledged continuous delivery implementation.
  • Setting up the development environment for .net core applications using Docker:
  • Source code management in VSTS : We'll have a look into the Git version control in VSTS and discuss branching strategies like trunk based development and how these concepts relate to continuous delivery.
  • Build management in VSTS : We'll see how to setup a Continuous integration build in VSTS that helps the code stay robust enough that team members can fearlessly make changes to the code base without worrying about breaking existing functionality.
  • Continuous testing : This section we’ll learn how to ensure that an application's components function correctly when assembled together. We'll see how to automate the tests and include them in your Continuous Integration scheme to get the most value from the tests.
  • Release management in VSTS : This section shows you how to do automatic deployments by using Release Management. You'll learn Release Management in VSTS, how it works and how to use release management to deploy our sample application to a Kubernetes cluster on Azure.

The course follows a phased approach to continuous delivery to automate build, deploy and management of .net core applications to Azure Container Services using VSTS ALM. By the end of this course, you'll have the necessary knowledge to create a fully automated build and release pipeline using Visual Studio Team Services for your .NET applications. And don't forget to check the course at https://www.packtpub.com/virtualization-and-cloud/continuous-delivery-visual-studio-team-services-video

Monday, September 28, 2015

PSScriptAnalyzer - Automate code checking for your PowerShell projects as part of TFS build

With WMF 5.0 we can make use of the PowerShell static code checker utility PSScriptAnalyzer to perform code analysis on PowerShell script files and modules. PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules. The rules are based on PowerShell best practices identified by PowerShell Team and the community. PSScriptAnalyzer generates DiagnosticResults (errors and warnings) to inform users about potential code defects and suggests possible solutions for improvements.

You can download the entire module from PowerShell gallery using the Install-Module cmdlet or create a pull request on the project at Github and build it yourself. Once you have the module available on the workstation you can perform code checking on PowerShell files by using the Invoke-ScriptAnalyzer cmdlet.

By making use of this cmdlets and the post-build script options from TFS build, you can now perform code checking on the PowerShell projects from the build server and choose to fail the build based on the results. Let’s see how this works.

First we need a function to do code checking using the Invoke-ScriptAnalyzer cmdlet and parse the results. The below content describes the process

function Get-DiagnosticIssue
{
       param
       (
              [Parameter(Mandatory=$true)]
              [ValidateNotNullOrEmpty()]
              [ValidateScript({Test-Path $_})]
              [string] $Path,

              [Parameter(Mandatory=$true)]
              [ValidateNotNullOrEmpty()]
              [string] $Severity,

              [bool] $FailOnIssues = $false
       )

       $logDirectory = Join-Path $Env:TF_BUILD_DROPLOCATION "Logs"
       if(-not(Test-Path $logDirectory -ErrorAction SilentlyContinue))
       {
              New-Item -ItemType Directory -Force -Path $logDirectory
       }
       $logFile = Join-Path $logDirectory "PSScriptAnalyzerLogs.log"

       Invoke-ScriptAnalyzer -Path $Path -Recurse |? {$_.Severity -ge $Severity} |fl | Out-File $logFile

       if($FailOnIssues)
       {
              if((Get-Content $logFile) -ne $null)
              {
                     $Host.UI.WriteErrorLine("PSScriptAnalyzer check failed. Please refer to the file $($logFile) for more details.")
              }
       }
}

Export-ModuleMember *

The Get-DiagnosticIssue function accepts a Severity parameter to filter the issues logged and a Path variable to perform analysis on all the scripts files and modules under that location. The FailOnIssues parameter can be used to decide whether the build should be failed or not. This module is called from a script file that is used as the post-build script path in the TFS build definition.

param
(
       [string] $Severity = "Information",
       [string] $Filter,
       [string] $FailOnIssues = "False"
)

$exitCode = 0
trap
{
    $Host.UI.WriteErrorLine($error[0].Exception.Message)
    $Host.UI.WriteErrorLine($error[0].Exception.StackTrace)
    if ($exitCode -eq 0)
    {
        $exitCode = 1
    }
}

$scriptName = $MyInvocation.MyCommand.Name
$scriptPath = Split-Path -Parent (Get-Variable MyInvocation -Scope Script).Value.MyCommand.Path

Push-Location $scriptPath
Import-Module .\PSScriptAnalyzerExtensions.psm1

$source = $env:TF_BUILD_BUILDDIRECTORY

if(-not ([string]::IsNullOrWhiteSpace($Filter)))
{
       $source = Get-ChildItem -Directory $env:TF_BUILD_BUILDDIRECTORY -Filter $Filter -Recurse |? {$_.FullName.ToUpper().Contains("Solution\$Filter".ToUpper())} | select -expand FullName
}

$failBuild = $FailOnIssues -eq "True"

Get-DiagnosticIssue -Path $source -Severity $Severity -FailOnIssues:$failBuild

Pop-Location

exit $exitCode

This script file is used in the process template as post-build script path with arguments as given below.



Next time the build is queued, it will trigger a code check using PSScriptAnalyzer and you can see the results in the log file generated.


Wednesday, July 29, 2015

Build and publish to NuGet as part of TFS build process

NuGet is a free, open source package management system for .NET platform, which helps in easy dependency management. Using NuGet very easy for project owners to build and define package dependencies which will be included in the package during the packaging process and later publish this to the repository for usage by external users.

Users can later install the package by searching in the NuGet source repository which will automatically download and install the dependencies as well. You can use the NuGet command line utility to create packages from a specification file and later publish them to the repository whenever needed. If you want to automate the process of package creation and publishing from a TFS build process, you can make use of custom PowerShell scripts that can be invoked as part of the build process. The Team Foundation Build template (TfvcTemplate.12.xaml) provides the capability to extend the build process by using PowerShell scripts at stages like Pre build and Post build.

You can use the default template to run PowerShell and batch (.bat) scripts before and after you compile your code, and before and after your run your tests. During the script execution you can make use of the Team foundation build environment variables to get key bits of data that you need for your build process logic.

I've created a PowerShell module that contains the functions that I need to build and publish a nuget package.

$ErrorActionPreference = "Stop"

Function Publish-NugetPackage
{
    param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string] $Project
    )
    # Read the product version from the assembly
    $version = Get-ChildItem -Filter "$($Project).dll" `
                             -Recurse `
                             -Path (Join-Path $env:TF_BUILD_BUILDDIRECTORY bin) `
                             -File | select -First 1 | select -expand VersionInfo | select -expand ProductVersion

    # Read the contents of the nuspec file
    $nuspecFile = Get-ChildItem -Filter "$($Project).nuspec" `
                                -Recurse `
                                -Path $env:TF_BUILD_SOURCESDIRECTORY -File | select -First 1

    $nuspecContents = Get-Content $nuspecFile.FullName

    # Replace the version of the nuspec file with the assembly version
    Set-Content -Path $nuspecFile.FullName `
                -Value ($nuspecContents -replace "[0-9]+(\.([0-9]+|\*)){1,3}", "$($version)
") `
                -Force
    # Create the nuget package
    New-NugetPackage $nuspecFile.FullName

    # Fetch the newly created nuget package
    $nugetPackage = Get-ChildItem -Filter "*.nupkg" `
                                  -Recurse `
                                  -Path $env:TF_BUILD_SOURCESDIRECTORY -File | select -First 1

    # Publish the nuget package to nuget repository
    Push-NugetPackage $nugetPackage.FullName

}

Function New-NugetPackage
{
    param
    (
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNull()]
        [ValidateScript({Test-Path $_})]
        [String] $NuspecFile,

        [Parameter(Position= 1)]
        [ValidateScript({Test-Path $_ -PathType Leaf -Include "nuget.exe"})]
        [String] $NugetLocation = (Join-Path $PSScriptRoot "nuget.exe")
    )

    $command = $NugetLocation + " pack $($NuspecFile)"

    Invoke-Expression $command
}

Function Push-NugetPackage
{
     param
    (

        [Parameter(Position= 3)]
        [string] $Source = "http://prajeeshnuget.azurewebsites.net/nuget",

        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNull()]
        [ValidateScript({Test-Path $_})]
        [string] $PackagePath,
       
        [Parameter(Position= 2)]
        [string] $APIKey = "MY_NUGET_APIKEY",

        [Parameter(Position= 1)]
        [ValidateScript({Test-Path $_ -PathType Leaf -Include "nuget.exe"})]
        [String] $NugetLocation = (Join-Path $PSScriptRoot "nuget.exe")
    )

    $command = $NugetLocation + " push $($PackagePath) $($APIKey)"
    if(-not ([String]::IsNullOrEmpty($Source)))
    {
        $command += " -s "  + $Source
    }

    Invoke-Expression $command | Out-Null
}

Export-ModuleMember -Function Publish*

The module contains logic to update the NuSpec file with the latest product version from the assembly that is build. Once updated this file will be used to create a nuget package and then published to the repository. As you can see, I’ve used the TF_BUILD_SOURCESDIRECTORY and TF_BUILD_BUILDDIRECTORY to get the source location and build location respectively in the module. To read more about TF_BUILD variables, refer to the link https://msdn.microsoft.com/en-us/library/hh850448.aspx.

I’ve created a script that I use to invoke the functions in this module

param
(
       [string]$Project
)

$exitCode = 0
trap
{
    $Host.UI.WriteErrorLine($error[0].Exception.Message)
    $Host.UI.WriteErrorLine($error[0].Exception.StackTrace)
    if ($exitCode -eq 0)
    {
        $exitCode = 1
    }
}


Import-Module .\TFSNugetExtensions.psm1
Publish-NugetPackage $Project
exit $exitCode

The next step is to publish these scripts along with the Nuget.exe file to the source control, so that I can refer these files as part of my build definition. I’ve added these files into the BuildExtensions folder in my team project

Now we can go ahead and create the build definition for our project. While creating the build definition it’s important to create the source settings mapping for the scripts folder so that they are also available as part of the build process.


In the process tab, you can now call the script which we have created as part of the post build execution phase.



That’s it, next time you queue a build, you can see that the build creates and uploads a nuget package to the repository automatically.