While NuGet provides all the power needed to explicitly control every aspect of a package (something the exacting control freak in me really appreciates), a simple project like this doesn’t need anything more than the standard conventions.

In a piece of recursion fit for a Christopher Nolan film, the easiest way to install the NuGet command line tooling so that we have it available to use from our build script is to use NuGet itself - from inside Visual Studio.

Now we can work out how to do it by hand, our usual prelude to automation. With a bit of work (details below), we end up with this command:

PS> .\packages\NuGet.CommandLine.4.1.0\tools\nuget.exe 
        pack .\src\Niche.CommandLine\Niche.CommandLine.csproj 
        -version 9.9.9 
        -outputdirectory .\build\packages 
        -basePath .\build 
        -properties Configuration=Debug

(The options are wrapped for readability; if you’re trying this out for yourself, they all need to be on the same line.)

In order for this to work, I needed to review of the packages.config file to ensure that the dependencies were nice and tidy. I removed some dependencies not currently required, and flagged a few that are only needed during development so they’re not forced upon library consumers.

If you look at the full packages.config file from the repo, you’ll see a large number of static code analysis packages, tools that I’m trying out to see how well they work. None of these are required to run the CommandLineProcessor itself, so I’ve marked all of them as developmentDependency="true".

Not everything associated with a NuGet package can be derived by convention, so we need a nuspec file with some key details listed:

<?xml version="1.0"?>
<package >
  <metadata>
    <id>Niche.CommandLineProcessor</id>
    <version>$version$</version>
    <authors>bevan@nichesoftware.co.nz</authors>
    <owners>bevan@nichesoftware.co.nz</owners>
    <projectUrl>
    https://github.com/theunrepentantgeek/Niche.CommandLineProcessor
   </projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>
      Convention based argument handling for console applications
    </description>
    <copyright>Copyright 2017</copyright>
    <tags>command line command-line option parser args arguments</tags>
  </metadata>
  <files>
    <file src="..\docs\ReadMe.txt" target="."/>
  </files>
</package>

The ReadMe.txt file that’s included will be automatically opened, by Visual Studio, when the package is installed as a quick reference reminder of the conventions used by the project.

We can now write the usual psake task to locate nuget.exe for us:

Task Requires.NuGet { 

    $script:nugetExe =
        resolve-path ".\packages\NuGet.CommandLine.*\tools\nuget.exe"

    if ($nugetExe -eq $null)
    {
        throw "Failed to find nuget.exe"
    }

    Write-Host "Found Nuget here: $nugetExe"
}

As before, we’re using a wildcard (*) for the version number so that we will always find it, regardless of the exact version available.

Next, a simple task to build the actual package:

Task Compile.NuGet -Depends Requires.NuGet, Requires.BuildType,
    Requires.BuildDir, Compile.Assembly, Configure.PackagesFolder {

    $nugetFolder = join-path $packagesFolder Niche.CommandLine
    mkdir $nugetFolder | Out-Null

    $csprojFile = resolve-path .\src\Niche.CommandLine\Niche.CommandLine.csproj

    exec {
        & $nugetExe pack $csprojFile -version $semver10 -outputdirectory $packagesFolder -basePath $buildDir -properties Configuration=$buildType
    }
}

Most of this task is stuff we’ve seen before.

We use the $semver10 version reference because these packages are going to be shared via NuGet.org; if we were using our own internal server, we’d use the semver 2.0 variable instead.

Prior post in this series:
Semantic versioning
Next post in this series:
Test Coverage with Opencover

Comments

blog comments powered by Disqus