Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it Possible To Use Both a Local NuGet Repository and Remote Repository

Tags:

nuget

I've been converting our library projects to NuGet packages and hosting them on an internal NuGet Feed. This is working great and has cut down on developers re-creating helper classes and "reinventing the wheel". Another huge plus is that other teams now can consume "released" libraries from our projects. Basically it's been a huge win so far.

The only problem we're facing is local builds. What we would like to do is is test libraries in our consuming projects before pushing a build to the NuGet feed. We're running into a problem because the projects that are consuming these libraries are setup to use the local feed (package restore on the build server allows our main trunk to build with the latest "released" libraries).

Is there a way to have local builds pick up from a local repository? I've begun working on an after build task for the libraries that creates local package files. Using the NuGet.config I think I should be able to mask certain repositories and then mask the config files on the build server. My theory is that when using a local build the local repository should be picked up and on the build server the feed would be used.

Is this possible? Is there anyone else that has documented how to do this?

Here is the after build task I'm using for creating the local packages:

  <PropertyGroup>
    <PackOutputDir>$([System.IO.Path]::Combine($(SolutionDir), "..\Prerelease"))</PackOutputDir>
    <BuildSpecCommand>$(NuGetCommand) spec $(ProjectFileName) -force -NonInteractive -Verbosity detailed</BuildSpecCommand>
    <PackCommand>$(NuGetCommand) pack $(ProjectFileName) -OutputDirectory "$(PackOutputDir)"</PackCommand>
  </PropertyGroup>
  <Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <Exec Command="$(BuildSpecCommand)" LogStandardErrorAsError="true" Condition=" '$(OS)' == 'Windows_NT' " />
    <Exec Command="$(PackCommand)" LogStandardErrorAsError="true" Condition=" '$(OS)' == 'Windows_NT' " />
  </Target>

I placed this NuGet.config at the root of our team project. This file is cloaked on the build server:

<configuration>
  <packageSources>
    <add key="NuGet official package source" value="https://nuget.org/api/v2/" />
    <add key="TestSource" value="Source\Prerelease" />
  </packageSources>
  <disabledPackageSources>
    <add key="LocalNuGetFeed" value="LocalNuGetFeed" />
  </disabledPackageSources>
  <activePackageSource>
    <add key="All" value="(Aggregate source)"  />
  </activePackageSource>
</configuration>

Here's the NuGet.config that I placed in a folder that should get picked up in the hierarchy on the build server:

<configuration>
  <packageSources>
    <add key="NuGet official package source" value="https://nuget.org/api/v2/" />
    <add key="LocalNuGetFeed" value="http://team2:12345/nuget" />
  </packageSources>
  <disabledPackageSources>
  </disabledPackageSources>
  <activePackageSource>
    <add key="All" value="(Aggregate source)"  />
  </activePackageSource>
</configuration>

Update Based on a provided answer I changed the nuget.targets file. Ideally I would not like to do this but if this is the best way to achieve what I'd like to accomplish then I am fine with this type of edit.

  <ItemGroup Condition=" '$(PackageSources)' == '' And '$Configuration' == 'Release'">
    <PackageSource Include="https://nuget.org/api/v2/" />
    <PackageSource Include="http://team2:12345/nuget/" />
  </ItemGroup>
  <ItemGroup Condition=" '$(PackageSources)' == '' And '$Configuration' != 'Release'">
    <PackageSource Include="https://nuget.org/api/v2/" />
    <PackageSource Include="C:\temp\NuGet\Prerelease" />
  </ItemGroup>

The idea here is to use the build task posted earlier for the library projects so that their packages are output to a temporary folder on disk. The code immediately above should be in the nuget.targets file for those projects which we will be needing to have any changes to the library update immediately while developers do work on their local machines, however the build server will only talk to our local feed during the team build process.

Is this correct?

Another idea... After discussing this with a co-worker we came up with another solution which may be more effective in practice. We decided to model it on the AvalonDock project. When you download sources and open the solution for that project you not only see the code to build the UI controls, but you also see an example project that uses all of the features of said controls.

His idea was that in our library projects where the code is just C# libraries that unit testing should be effective enough to cover any issues. Also the builds that push these libraries are gated, meaning that only apply the checkins if the build (and tests) complete.

For the UI controls he pointed to the above example for AvalonDock. Including a project that utilized all the controls should mitigate most issues. Since unit testing on UI controls is limited it would still put the onus on the developer to check the controls within the test project before committing the code and starting the build process.

What is a general opinion of this approach?

like image 253
Mike G Avatar asked Feb 12 '13 00:02

Mike G


1 Answers

You can definitely use multiple repositories at once. The important part here is that you need to define the order in which you want them to be used. When restoring/installing a package, NuGet will first look on the first repository, if not found it will scan the second repository, and so on.

If you need the local repository to get priority over the "released" repository, you'll need to ensure the local repository is the first one in the list.

Your approach looks OK on first sight, although you could also go for an MSBuild solution (without these config modifications) using the .nuget\NuGet.targets file that comes with NuGet package restore. Define your feeds by adding them in the <PackageSources> element, and then (maybe based on Build configuration Debug | Release) you can switch the repo to be used in the <RestoreCommand>.

like image 65
Xavier Decoster Avatar answered Oct 06 '22 16:10

Xavier Decoster