TimMarsh
TimMarsh

Reputation: 11

Nuget Update Packages.config in MSBuild BeforeBuild Step

I have been trying to write an MsBuild task to automatically get Nuget packages from a feed url and automatically update the packages.config to update to the latest version.

 // ---- Download and install a package at a desired path ----
  var sourceUri = new Uri("FEED URL");

  // ---- Update the ‘packages.config’ file ----
  var packageReferenceFile = new PackageReferenceFile("../../packages.config");
  string packagesPath = "../../packages";
  IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository(sourceUri.ToString());
  PackageManager packageManager = new PackageManager(sourceRepository, packagesPath);

  foreach (var sourcePackage in sourceRepository.GetPackages().Where(x => x.IsLatestVersion))
  {
    if (!packageReferenceFile.EntryExists(sourcePackage.Id + " " + sourcePackage.Version, sourcePackage.Version))
    {
      var oldPackage = packageReferenceFile.GetPackageReferences().FirstOrDefault(x => x.Id.Contains(sourcePackage.Id));

      if (oldPackage != null)
      {
        packageReferenceFile.DeleteEntry(oldPackage.Id, oldPackage.Version);
      }

      packageManager.InstallPackage(sourcePackage.Id, SemanticVersion.Parse(sourcePackage.Version.ToFullString()));

      // Get the target framework of the current project to add --> targetframework="net452" attribute in the package.config file
      var currentTargetFw = Assembly.GetExecutingAssembly()
        .GetCustomAttributes(typeof(TargetFrameworkAttribute), false);
      var targetFrameworkAttribute = ((TargetFrameworkAttribute[]) currentTargetFw).FirstOrDefault();

      // Update the packages.config file    
      packageReferenceFile.AddEntry(sourcePackage.GetFullName(),
        SemanticVersion.Parse(sourcePackage.Version.ToFullString()), false,
        new FrameworkName(targetFrameworkAttribute.FrameworkName));
    }
  }

This is working fine as a console app and is automatically reading the file correctly and updating the necessary references.

When i try to run this as an MsBuild task I keep running into errors.

This is the code I have put in the csproj (also moved to the nuget.targets to test)

<Target Name="BeforeBeforeBuild" BeforeTargets="BeforeBuild">
    <UpdateNugetFiles />
  </Target>
<UsingTask TaskName="UpdateNugetFiles" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" > 
    <Task>
        <Reference Include="System.Core" />
        <Using Namespace="System" />
        <Using Namespace="System.Linq" />
        <Using Namespace="System.Reflection" />
        <Using Namespace="System.Runtime.Versioning" />
        <Using Namespace="NuGet" />
        <Code Type="Fragment" Language="cs">
            <![CDATA[
            try {
                // ---- Download and install a package at a desired path ----
  var sourceUri = new Uri("FEED URL");

  // ---- Update the ‘packages.config’ file ----
  var packageReferenceFile = new PackageReferenceFile("../../packages.config");
  string packagesPath = "../../packages";
  IPackageRepository sourceRepository = PackageRepositoryFactory.Default.CreateRepository(sourceUri.ToString());
  PackageManager packageManager = new PackageManager(sourceRepository, packagesPath);

  foreach (var sourcePackage in sourceRepository.GetPackages().Where(x => x.IsLatestVersion))
  {
    if (!packageReferenceFile.EntryExists(sourcePackage.Id + " " + sourcePackage.Version, sourcePackage.Version))
    {
      var oldPackage = packageReferenceFile.GetPackageReferences().FirstOrDefault(x => x.Id.Contains(sourcePackage.Id));

      if (oldPackage != null)
      {
        packageReferenceFile.DeleteEntry(oldPackage.Id, oldPackage.Version);
      }

      packageManager.InstallPackage(sourcePackage.Id, SemanticVersion.Parse(sourcePackage.Version.ToFullString()));

      // Get the target framework of the current project to add targetframework="net452" attribute in the package.config file
      currentTargetFw = Assembly.GetExecutingAssembly()
        .GetCustomAttributes(typeof(TargetFrameworkAttribute), false);
      var targetFrameworkAttribute = ((TargetFrameworkAttribute[]) currentTargetFw).FirstOrDefault();

      // Update the packages.config file    
      packageReferenceFile.AddEntry(sourcePackage.GetFullName(),
        SemanticVersion.Parse(sourcePackage.Version.ToFullString()), false,
        new FrameworkName(targetFrameworkAttribute.FrameworkName));
    }
  }

                return true;
            }
            catch (Exception ex) {
                Log.LogErrorFromException(ex);
                return false;
            }
        ]]>
        </Code>
    </Task>
</UsingTask>

Any ideas on how to resolve this as cannot seem to find a solution. Overall what to run this a pre step on a CI build to keep nugets up to date.

Thanks Tim

Upvotes: 1

Views: 2638

Answers (2)

Leo Liu
Leo Liu

Reputation: 76928

Nuget Update Packages.config in MSBuild BeforeBuild Step

Not sure where your code issue comes from. It may be simpler just use NuGet.exe to restore and update the solution instead of trying to use C# code.

So you could add following nuget command line in the MSBuild BeforeBuild Step

  <Target Name="BeforeBeforeBuild" BeforeTargets="BeforeBuild">
    <Exec Command="$(YourNuGetPath)\nuget.exe restore &quot;$(YouSolutionPath)\YourSolution.sln&quot; -PackagesDirectory &quot;$(YouPackagePath)\packages&quot;" />
    <Exec Command="$(YourNuGetPath)\nuget.exe update &quot;$(YouSolutionPath)\YourSolution.sln&quot;" />
  </Target>

Note: If you are using Visual Studio, Visual Studio will automatically check the missing packages during the build and restore them: Package Restore.

Hope this helps.

Upvotes: 0

C.J.
C.J.

Reputation: 16111

Just call

nuget restore "your_solution.sln"

Don't reinvent the wheel by writing it in C# code.

Upvotes: 1

Related Questions