Showing posts with label NuGet. Show all posts
Showing posts with label NuGet. Show all posts

Sunday, August 16, 2015

Software package management using PowerShell OneGet, DSC, Chef and Chocolatey

Converting your software shared repositories to a managed approach with the use of a package management system that automates the process of installing, upgrading, configuration and removal of software packages in a consistent manner is a challenging task for IT.

The idea is to distribute software installation packages that contains additional metadata like, name, version, purpose, vendor, checksum etc. that will be used in an effective manner to manage dependencies and other details that are needed for the software to run properly. Having a package management system like this, will make easier to find, install, and remove software packages in a consistent manner.

In a windows infrastructure, you can make use of the tools like chocolatey, PowerShell package management and chef to automate and create an effective package management infrastructure that converts your infrastructure as code and thus maintaining an efficient process of software installations in your company.

Without much effort you can easily setup a chocolatey repository for your packages in Azure, and then later configure this as a source in PowerShell OneGet to install packages from this source. Later you can combine this with DSC or Chef to automatically install the packages and maintain the servers in a desired state based on the configuration.

A detailed tutorial on this series can be found at the posts from the links given below:




Saturday, August 1, 2015

Setup your Chocolatey repository in Azure - Part 2

In the first part of this series we've seen how we can have our chocolatey repository hosted on Azure, we can start pushing and using some packages from the server.

To create and publish packages you’ll need nuget executable on your workstation. You can download the nuget.exe from the link https://www.nuget.org/nuget.exe.

The next step is to create a nuspec file with the details of the package you want to create. In this sample I’ll create a nuspec file for creating a package for the Foxe XML editor and push that to the chocolatey repository.

Create a folder foxe-package in your workstation and add the nuspec file with the contents as given below.

xml version="1.0" encoding="utf-8"?>
<package xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <metadata xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
        <id>Foxe</id>
        <version>1.2.0</version>
        <title>Firstobject's free XML editor for Windows</title>
        <authors>Firstobject</authors>
        <owners>Firstobject</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Free XML editor for Windows</description>
        <summary>
          It loads big files (multi-megabyte) fast and lets you format XML and edit HTML and any loosely formed XML or other markup.
          The tree view is editable and customizable for useful navigation.
        </summary>
        <language>en-US</language>
        <tags>XML, Windows, Free, Tools, Editor</tags>       
    </metadata>
</package>

Now create a Tools folder under the foxe-package folder and add a chocolateyinstall.ps1 file with the contents

Install-ChocolateyPackage 'Foxe' 'exe' '/quiet' 'http://www.firstobject.com/foxesetup242.exe'

This will download the installer from the url mentioned in the script and install it on the workstation. We've use the Install-ChocolateyPackage command to run the installer downloaded from the FirstObject website. You can also make use of other commands available to further customize your installation process. For a full list of commands refer the wiki here https://github.com/chocolatey/chocolatey/wiki/HelpersReference 

After creating the nuspec file, we’ll use the pack command of the nuget executable to create a nupkg file that will be pushed to the repository.


PS C:\Packages\foxe-package> .\nuget.exe pack .\Foxe.nuspec
Attempting to build package from 'Foxe.nuspec'.
Successfully created package 'C:\Packages\foxe-package\Foxe.1.2.0.nupkg'.

WARNING: 1 issue(s) found with package 'Foxe'.

Issue: Unrecognized PowerShell file.
Description: The script file 'tools\chocolateyinstall.ps1' is not recognized by NuGet and hence will not be executed during installation of this package
.
Solution: Rename it to install.ps1, uninstall.ps1 or init.ps1 and place it directly under 'tools'.


Now we have the package ready, lets push this to our chocolatey repository


PS C:\Scripts\Chocolatey> .\nuget.exe push .\Foxe.1.2.0.nupkg "YOUR_API_KEY" -s http://prajeeshchoco.azurewebsites.net/
Pushing Foxe 1.2.0 to 'http://prajeeshchoco.azurewebsites.net/'...
Your package was pushed.


You can list the packages available on the server by using the list command, to verify the packages available.


PS C:\Scripts\Chocolatey> .\nuget.exe list -s http://prajeeshchoco.azurewebsites.net/nuget -allversions
Foxe 1.0.0
Foxe 1.1.0
Foxe 1.2.0



Next we can try to install this package using chocolatey on the workstation. For installation, open PowerShell as Administrator and execute the command

iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))
and press enter. This will install Chocolatey on the machine.



Now you can use the choco command to install the package from the server as given below.


Next we’ll use PowerShell PackageManagement which is a unified interface to package management systems to make Software Discovery, Installation and Inventory (SDII) work via a common set of cmdlets. We’ll add this repository to the OneGet sources and install packages from here. That's in the next post.

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.

Wednesday, July 22, 2015

Using PowerShell to Create, Publish, Read and Remove NuGet packages





I’ve created some simple functions to do these actions using the nuget.exe executable and put in a module. These can be also used to hook it up with the TFS build process as post-build scripts to publish the packages directly to NuGet server after a successful build.

Function Get-NugetPackages
{   
    param
    (
        [String] $Source = "http://prajeeshnuget.azurewebsites.net/nuget",
        [switch] $IncludePreRelease,
        [switch] $AllVersions,

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

    $command = $NugetLocation + " list "

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

    if($IncludePreRelease)
    {
        $command += " -Prerelease"
    }

    if($AllVersions)
    {
        $command += " -AllVersions"
    }

    Invoke-Expression $command
}

Function UnPublish-NugetPackage
{
    param
    (
        [string] $Source = "http://prajeeshnuget.azurewebsites.net",

        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNull()]
        [switch] $PackageId,

        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateNotNull()]
        [switch] $Version,

        [string] $APIKey = "MYKEY",

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

    $command = $NugetLocation + " delete $($PackageId) $($Version) $($APIKey) -NoPrompt"
    if(-not ([String]::IsNullOrEmpty($Source)))
    {
        $command += " -s "  + $Source
    }

    Invoke-Expression $command
}

Function Publish-NugetPackage
{
    param
    (
        [string] $Source = "http://prajeeshnuget.azurewebsites.net",

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

        [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
}

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

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

        [string] $OutputDirectory
    )
    $command = $NugetLocation + " pack $($NuspecPath)"

    if(-not ([String]::IsNullOrEmpty($OutputDirectory)))
    {
        $command += " -OutputDirectory "  + $OutputDirectory
    }

    Invoke-Expression $command
}

Export-ModuleMember -Function *-Nuget*

You can also download the module from GitHub from https://goo.gl/cQbBD3