4
votes

I have an ASP.NET MVC 5 project that I am trying to build on our company build server using MSBuild, however the build fails to restore NuGet packages. I am using Visual Studio 2015 and TFS.

My project structure is as follows:

  • Solution (.sln)
  • .nuget
    • NuGet.config
    • NuGet.targets
  • Project Folder
    • Project items (references, libraries etc)
  • Project.Test.Unit
    • Unit test items

Here is my NuGet.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <solution>
    <add key="disableSourceControlIntegration" value="true" />
  </solution>
</configuration>

Here is my NuGet.targets file:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>

    <!-- Enable the restore command to run before builds -->
    <RestorePackages Condition="  '$(RestorePackages)' == '' ">true</RestorePackages>

    <!-- Property that enables building a package from a project -->
    <BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>

    <!-- Determines if package restore consent is required to restore packages -->
    <RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">false</RequireRestoreConsent>

    <!-- Download NuGet.exe if it does not already exist -->
    <DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">false</DownloadNuGetExe>
  </PropertyGroup>

  <ItemGroup Condition=" '$(PackageSources)' == '' ">
    <!-- Package sources used to restore packages. By default, registered sources under %APPDATA%\NuGet\NuGet.Config will be used -->
    <!-- The official NuGet package source (https://www.nuget.org/api/v2/) will be excluded if package sources are specified and it does not appear in the list -->
    <!--
            <PackageSource Include="https://www.nuget.org/api/v2/" />
            <PackageSource Include="https://my-nuget-source/nuget/" />
        -->
    <PackageSource Include="\\itliv-nas03\Development Team\NuGet\Packages" />
  </ItemGroup>

  <PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
    <!-- Windows specific commands -->
    <NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
    <PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
    <!-- We need to launch nuget.exe with the mono command if we're not on windows -->
    <NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
    <PackagesConfig>packages.config</PackagesConfig>
  </PropertyGroup>

  <PropertyGroup>
    <!-- NuGet command -->
    <NuGetExePath Condition=" '$(NuGetExePath)' == '' ">\\itliv-nas03\Development Team\NuGet\NuGet.exe</NuGetExePath>
    <PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>

    <NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
    <NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>

    <PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>

    <RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
    <NonInteractiveSwitch Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' ">-NonInteractive</NonInteractiveSwitch>

    <PaddedSolutionDir Condition=" '$(OS)' == 'Windows_NT'">"$(SolutionDir) "</PaddedSolutionDir>
    <PaddedSolutionDir Condition=" '$(OS)' != 'Windows_NT' ">"$(SolutionDir)"</PaddedSolutionDir>

    <!-- Commands -->
    <RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)"  $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)</RestoreCommand>
    <BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols</BuildCommand>

    <!-- We need to ensure packages are restored prior to assembly resolve -->
    <BuildDependsOn Condition="$(RestorePackages) == 'true'">
      RestorePackages;
      $(BuildDependsOn);
    </BuildDependsOn>

    <!-- Make the build depend on restore packages -->
    <BuildDependsOn Condition="$(BuildPackage) == 'true'">
      $(BuildDependsOn);
      BuildPackage;
    </BuildDependsOn>
  </PropertyGroup>

  <Target Name="CheckPrerequisites">
    <!-- Raise an error if we're unable to locate nuget.exe  -->
    <Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
    <!--
        Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
        This effectively acts as a lock that makes sure that the download operation will only happen once and all
        parallel builds will have to wait for it to complete.
        -->
    <MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT;DownloadNuGetExe=$(DownloadNuGetExe)" />
  </Target>

  <Target Name="_DownloadNuGet">
    <DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
  </Target>

  <Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
    <Exec Command="$(RestoreCommand)"
          Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />

    <Exec Command="$(RestoreCommand)"
          LogStandardErrorAsError="true"
          Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
  </Target>

  <Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
    <Exec Command="$(BuildCommand)"
          Condition=" '$(OS)' != 'Windows_NT' " />

    <Exec Command="$(BuildCommand)"
          LogStandardErrorAsError="true"
          Condition=" '$(OS)' == 'Windows_NT' " />
  </Target>

  <UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <OutputFilename ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.Core" />
      <Using Namespace="System" />
      <Using Namespace="System.IO" />
      <Using Namespace="System.Net" />
      <Using Namespace="Microsoft.Build.Framework" />
      <Using Namespace="Microsoft.Build.Utilities" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
                try {
                    OutputFilename = Path.GetFullPath(OutputFilename);

                    Log.LogMessage("Downloading latest version of NuGet.exe...");
                    WebClient webClient = new WebClient();
                    webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);

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

I have tried the following:

Added this code to the NuGet.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <solution>
    <add key="disableSourceControlIntegration" value="true" />
  </solution>
  <packageSources>
    <add key="itliv" value="\\itliv-nas03\Development Team\NuGet\Packages" />
  </packageSources>
  <activePackageSource>
    <add key="All" value="\\itliv-nas03\Development Team\NuGet\Packages" />
  </activePackageSource>
</configuration>
  • Tried running through command line using:

nuget restore path\to\solution.sln which returns the following error:

WARNING: Unable to find version '3.4.1.9004' of package 'Antlr'.
  C:\Users\it-chrism\.nuget\packages\: Package 'Antlr.3.4.1.9004' is not found on source 'C:\Users\it-chrism\.nuget\packages\'.
  C:\Users\it-chrism\AppData\Local\NuGet\Cache: Package 'Antlr.3.4.1.9004' is not found on source 'C:\Users\it-chrism\AppData\Local\NuGet\Cache'.

Here is my error message when attempting to build:

Summary
Release | Any CPU
 1 error(s), 0 warning(s)
$/Develop/Websites/VehicleLookupUI/VehicleLookupWebUI.sln - 1 error(s), 0 warning(s), View Log File
 C:\Builds\1\Develop\VehicleLookupWeb-Develop\Sources\VehicleLookupUI\VehicleLookupWebUI\VehicleLookupWebUI.csproj (315): This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is ..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props.
 $/Develop/Websites/VehicleLookupUI/VehicleLookupWebUI.sln compiled
 No Test Results
 No Code Coverage Results
Other Errors and Warnings
 2 error(s), 0 warning(s)
 Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.

 TF270015: 'MSBuild.exe' returned an unexpected exit code. Expected '0'; actual '1'.

I have a feeling that NuGet is looking in the wrong folder for the missing packages. I can include the sources in Tools > NuGet Package Manager.. > Package Manager Settings > NuGet Package Manager > Package Sources but this only works for me locally using Visual Studio and not using MSBuild attempting to build it 'out of the box'.

I am attempting to build on TSF by opening up Team Explorer > Builds, then right-clicking on my build and selecting Queue New Build...

2
Please provide the complete about the command NuGet restore path\to\solution.sln, does it restore success.Zhanglong Wu - MSFT

2 Answers

3
votes

You are using MSBuild-Integrated way to restore package, for this way, there is .nuget folder (contains nuget.exe, nuget.config and nuget.targets) in solution and need to be added to source control and you don’t need to add Nuget Restore build step/task to your build definition to restore package, so remove that step/task and set Clean to true in Repository tab of your build definition. I recommended that you migrate to automatic restore:

  1. Close Visual Studio to avoid file potential file locks and conflicts.
  2. If using TFS: a. Remove nuget.exe and nuget.targets from the solution's .nuget folder and remove those files from the solution workspace. a. Retain nuget.config with the disableSourceControlIntegration setting as explained in Omitting packages with Team Foundation Version Control.
  3. If not using TFS: a. Remove the .nuget folder from the solution and the solution workspace.
  4. Edit each project file in the solution, remove the <RestorePackages> element, and remove any references to the nuget.targets file.

More information, you can refer to this article.

0
votes

Please special Nuget.config file on TFS build server on the following location. enter image description here