Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NuGet release management

I have for the first time made something I want to share on NuGet, but I am not sure how this "release preparation" is done.

At the moment my following steps are:

  1. Manually change the assembly version of my main assembly (MyAssembly) in AssemblyInfo.cs from 1.0.0.0 to 1.1.0.0
  2. Build the main assembly release version in Visual Studio
  3. Pack the release for my main assembly (nuget pack -prop configuration=release == MyAssembly.1.1.0.0.nupkg)
  4. Publish this package to NuGet (nuget push MyAssembly.1.1.0.0.nupkg)
  5. Update the NuGet packages for assemblies referring MyAssembly (e.g. MyAssembly.Web.Mvc gets its MyAssembly updated from v1.0.0.0 -> v1.1.0.0 using the NuGet Package Manager) defined in packages.config
  6. Change the version AssemblyInfo.cs of MyAssembly.Web.Mvc to 1.1.0.0, build release, NuGet pack and publish
  7. Repeat step 6 for all my references assemblies

This is some steps that are a PITA, and I will some day make an error and break the release.

This got me think, am I missing a crucial point, am I doing all this wrong?

UPDATE

Based on the knowledge @ialekseev provided, I have now created this:

Build.ps1

Param(
    [Parameter(Mandatory=$true)]
    [string]$version,
    [string]$configuration = "Release",
    [boolean]$tests = $false,
    [boolean]$publish = $false,
    [boolean]$pack = $false,
    [string]$outputFolder = "build\packages"
)

# Include build functions
. "./BuildFunctions.ps1"

# The solution we are building
$solution = "NerveFramework.sln"
$assemblies = "NerveFramework", "NerveFramework.Web", "NerveFramework.Web.Mvc", "NerveFramework.Web.WebApi"

# Start by changing the assembly version
Write-Host "Changing the assembly versions to '$version'..."
$assemblyInfos = Get-ChildItem $assemblies -Filter "AssemblyInfo.cs" -Recurse | Resolve-Path -Relative
foreach ($assemblyInfo in $assemblyInfos) {
    ChangeAssemblyVersion $assemblyInfo $version
}

# Build the entire solution
Write-Host "Cleaning and building $solution (Configuration: $configuration)"
BuildSolution $solution $configuration

# Change dependency version on all depending assemblies
Write-Host "Changing the NerveFramework(s) NuGet Spec version dependencies to '$version'..."
$nuspecs = Get-ChildItem $assemblies -Filter "NerveFramework*.nuspec" -Recurse | Resolve-Path -Relative
foreach ($nuspec in $nuspecs) {
    ChangeNugetSpecDependencyVersion $nuspec "NerveFramework" $version
} 

# Pack the assemblies and move to output folder
if ($pack) {
    Write-Host "Packaging projects..."
    $projects = Get-ChildItem $assemblies -Filter "NerveFramework*.csproj" -Recurse | Resolve-Path -Relative
    foreach ($project in $projects) {
        PackProject $project $configuration $outputFolder
    } 
}

# Publish the assemblies
if ($publish) {
    Write-Host "Publishing packages..."
    $packages = Get-ChildItem $outputFolder -Filter "*$version.nupkg" -Recurse | Resolve-Path -Relative
    foreach ($package in $packages) {
        PublishPackage $package
    } 
}

BuildFunctions.ps1

Function BuildSolution() {

    Param(
        [Parameter(Mandatory=$true)]
        [string]$solution,
        [Parameter(Mandatory=$true)]
        [string]$configuration
    )

    # Set the path to the .NET folder in order to use "msbuild.exe"
    $env:PATH = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319"

    Invoke-Expression "msbuild.exe $solution /nologo /v:m /p:Configuration=$configuration /t:Clean"
    Invoke-Expression "msbuild.exe $solution /nologo /v:m /p:Configuration=$configuration /clp:ErrorsOnly"
}

Function ChangeAssemblyVersion() {

    Param(
        [Parameter(Mandatory=$true)]
        [string]$filePath,
        [Parameter(Mandatory=$true)]
        [string]$publishVersion
    )

    Write-Host "-- Updating '$filePath' to version '$publishVersion'"

    $assemblyVersionPattern = 'AssemblyVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)'
    $assemblyVersion = 'AssemblyVersion("' + $publishVersion + '")';
    $assemblyFileVersionPattern = 'AssemblyFileVersion\("[0-9]+(\.([0-9]+|\*)){1,3}"\)'
    $assemblyFileVersion = 'AssemblyFileVersion("' + $publishVersion + '")';

    (Get-Content $filePath -Encoding utf8) | ForEach-Object { 
            % { $_ -Replace $assemblyVersionPattern, $assemblyVersion } |
            % { $_ -Replace $assemblyFileVersionPattern, $assemblyFileVersion } 
    } | Set-Content $filePath
}

Function ChangeNugetSpecDependencyVersion() {

    Param(
        [Parameter(Mandatory=$true)]
        [string]$filePath,
        [Parameter(Mandatory=$true)]
        [string]$packageId,
        [Parameter(Mandatory=$true)]
        [string]$publishVersion
    )

    [xml] $toFile = (Get-Content $filePath)
    $nodes = $toFile.SelectNodes("//package/metadata/dependencies/dependency[starts-with(@id, $packageId)]")
    if ($nodes) {
        foreach ($node in $nodes) {
            $nodeId = $node.id
            Write-Host "-- Updating '$nodeId' in '$filePath' to version '$publishVersion'"
            $node.version = "[" + $publishVersion +"]"
            $toFile.Save($filePath)
        }
   }
}

Function PackProject() {

    Param(
        [Parameter(Mandatory=$true)]
        [string]$project,
        [Parameter(Mandatory=$true)]
        [string]$configuration,
        [Parameter(Mandatory=$true)]
        [string]$outputFolder
    )

    if (!(Test-Path -Path $outputFolder)) {
        New-Item $outputFolder -Type Directory
    }

    Write-Host "-- Packaging '$project'"
    Invoke-Expression ".nuget\NuGet.exe pack $project -OutputDirectory '$outputFolder' -Prop Configuration=$configuration"
}

Function PublishPackage() {

    Param(
        [Parameter(Mandatory=$true)]
        [string]$package
    )

    Write-Host "-- Publishing '$package'"
    Invoke-Expression ".nuget\NuGet.exe push $package"

}

Run like .\Build -version 1.2.0.0 -pack $true

like image 749
janhartmann Avatar asked Oct 31 '22 10:10

janhartmann


1 Answers

You need to automate you procedure, because, yes, doing it manually is very error-prone process.

I usually write powershell/cmd scripts that could perform the following steps:

  1. Build solution
  2. Run tests over it
  3. Update assemblies versions
  4. Create NuGet packages
  5. Publish NuGet packages

Then you could just run it locally to go through all these steps automatically. Also you could delegate some tasks to your Build-server (if you have one). E.g. Teamcity could take responsibility for building, running tests, and even publishing packages to NuGet. Anyway, I like to have all these scripts in my source control to be able to run them locally whenever I want to. If you are interested, you could review scripts I wrote for one of my projects on GitHub. Scripts are in build folder and publish_local.cmd is an entry point. Project has multiple NuGet dependencies, so, I believe it's similar to what you are trying to accomplish.

I know it's better to provide examples directly in the answer, but there are too many scripts to include here. If you have any questions, please be my guest.

like image 100
ialekseev Avatar answered Nov 15 '22 06:11

ialekseev