Ignore NuGet package restore on .vdproj projects in Azure Pipelines - msbuild

I'm attempting to set up an Azure DevOps build pipeline against a .NET Framework 4.7.2 solution which contains a Visual Studio Installer Project. I've set up a self-hosted agent on a Windows Server 2019 VM, which has Visual Studio 2019 Community installed. The build pipeline contains the NuGet Installer task, followed by the NuGet task, set up to restore the referenced NuGet Packages. Below is the YAML snippet:
- task: NuGetCommand#2
inputs:
command: 'restore'
restoreSolution: '$(solution)'
Running a build with this configuration however, results in the following error in the build logs:
[error]The nuget command failed with exit code(1) and error(C:\##############.vdproj(1,1): error MSB4025: The project file could not be loaded. Data at the root level is invalid. Line 1, position 1.)
This appears to be due to a performance enhancement that's been made in newer versions of nuget.exe. The suggestion, based on this GitHub issue, is to enable skipping non-existent package targets using the RestoreUseSkipNonexistentTargets MSBuild setting.
The GitHub issue mentions using the NUGET_RESTORE_MSBUILD_ARGS NuGet CLI environment variable in order to set this property, but I don't know how this can be achieved through the NuGet build task.
Since NuGet is now integrated with MSBuild, I then attempted to set this property to false through a command-line argument on the NuGet task. I modified the YAML, setting the command to custom in order to pass arguments. I based the syntax off of the MSBuild restore documentation. It now looks like follows:
- task: NuGetCommand#2
inputs:
command: 'custom'
arguments: 'restore "$(solution)" -p:RestoreUseSkipNonexistentTargets=false'
This build configuration results in the following error:
[error]The nuget command failed with exit code(1) and error(Unknown option: '-p:RestoreUseSkipNonexistentTargets=false')
My question is, how do I go about getting the NuGet restore task to skip package restore on .vdproj projects?
EDIT
The other project in the solution is a C# WinForms .NET Framework project. We're using packages.config rather than PackageReference.

As for your original issue: MSB4025
As you mentioned above, it's one open issue here. Anyone interested at it can track the issue there.
[error]The nuget command failed with exit code(1) and error(Unknown
option: '-p:RestoreUseSkipNonexistentTargets=false')
The nuget restore command won't recognize a msbuild property. See similar issue and more details here.
Since The other project in the solution is a C# WinForms .NET Framework project. We're using packages.config rather than PackageReference.
A workaround for this is to use nuget custom command like this:
- task: NuGetCommand#2
inputs:
command: 'custom'
arguments: 'restore YourProjectName\packages.config -PackagesDirectory $(Build.SourcesDirectory)\packages'
This can skip the restore step for the installer project.

In general you do not need to called nuget restore explicitly anymore. MSBuild does it automatically as part of the build (so you're likely doing it twice). You can add the p:RestoreUseSkipNonexistentTargets=false property to the MSBuild arguments of a VSBuild task or a DotNet build or publish task:
- task: DotNetCoreCLI#2
displayName: Build/Publish
inputs:
command: 'publish'
publishWebProjects: false
projects: '$(solution)'
arguments: '-r $(runtimeIdentifier) /p:RestoreUseSkipNonexistentTargets=false'
zipAfterPublish: false
modifyOutputPath: false

The best way i found :
use 3 tasks on the pipeline tested on vs2022 hosted image
All the tasks uses the Visual Studio 2022 Developer PowerShell.
Task 1 - restore nuget with ignoring the error of the unsupported vdproj
Task 2 - Build the solution with msbuild will not build the vdproj
Task 3 - Build the vdproj only using DevEnv
- task: PowerShell#2
displayName: "restore nuget"
inputs:
targetType: 'inline'
script: |
& 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\Launch-VsDevShell.ps1'
msbuild -t:restore .\<solution>.sln -p:RestoreUseSkipNonexistentTargets=false
ignoreLASTEXITCODE: true
pwsh: true
- task: PowerShell#2
displayName: "build solution"
inputs:
targetType: 'inline'
script: |
& 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\Launch-VsDevShell.ps1'
msbuild .\<solution>.sln
pwsh: true
- task: PowerShell#2
displayName: "create install "
inputs:
targetType: 'inline'
script: |
& 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\Launch-VsDevShell.ps1'
devenv ".\<project>.vdproj" /Build
pwsh: true

Related

Create Pipelines in Azure DevOps in a big project

I would like to fully automate my current application deployment process.
I have big project in Azure DevOps. Code was writen on C# for .Net core.
The Solution consists 3 sites and 2 windows service application (build to msi file).
When I was creating Pipelines and choose "Azure Repos Git" and click on my project then in Configure your pipeline choose "ASP.NET CORE".
On "Review your pipeline YAML" I have a problems.
How can I in YAML file point to the site I want to build?
How can I in YAML file point to the site I want to build?
When you use the Asp.net Core Yaml template, it will use the dotnet build script to build your project. You could add the target path to the dotnet build command.
For example:
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
variables:
buildConfiguration: 'Release'
steps:
- script: dotnet build **/*.csproj --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
On the other hand, I recommand you to use the task to run the build.
- task: DotNetCoreCLI#2
inputs:
command: 'build'
projects: '**/*.csproj'
arguments: '--configuration $(BuildConfiguration)'
You could add the specific path is in the projects field.
Here is a doc about DotNetCoreCLI task and Task introduction.

Remove a DLL from the bin folder in the Build Pipeline

I have the following build script which is not working with Azure Devops Build Pipelines. After Building the solution, I am trying to delete a specific DLL from the bin folder which works locally but not in the build pipeline.
<PropertyGroup>
<PostBuildEvent>
cd $(TargetDir)
del Sample.dll
</PostBuildEvent>
</PropertyGroup>
Build Solution Definition
steps:
- task: VSBuild#1 displayName: 'Build solution' inputs:
solution: '$(Parameters.solution)'
vsVersion: 15.0
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=false /p:SkipInvalidConfigurations=true /p:PackageLocation="$(Build.ArtifactStagingDirectory)\\" /p:Configuration=Release'
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
maximumCpuCount: true
Delete
steps:
- task: DeleteFiles#1
displayName: 'Delete files from $(Build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '$(Build.ArtifactStagingDirectory)'
Contents: |
\Sage.Common.LinqBridge*\
\Sage.Common.LinqBridge.dll*\
Publish
steps:
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact'
inputs:
ArtifactName: '$(Parameters.ArtifactName)'
condition: succeededOrFailed()
Solution:
Thank you #Levi Lu-MSFT in helping me with the solution.
In the delete task, changing the delete pattern worked. For reference,
steps:
- task: DeleteFiles#1
displayName: 'Delete files from $(Build.ArtifactStagingDirectory)'
inputs:
SourceFolder: '$(Build.ArtifactStagingDirectory)'
Contents: '**\Sage.Common.LinqBridge.dll'
Remove a DLL from the bin folder in the Build Pipeline
I have created a sample to test, and it works fine on my side.
To resolve this issue, I would like provide following trouleshootings:
Check the build log, to found out if the PostBuildEvent is executed successfully.
Make sure you have specify the correct MSBuild arguments in the build task, like: /property:Configuration=Release:
If you are using the private agent, make sure you have permission to delete file from the private agent. Or you can test it with hosted agent.
Update:
According to the error log, we could to know you are publishing the project and delete the one .dll file in the post build event.
If you check the log, you will find MSBuild get the files from the folder obj\Release\Package\PackageTmp\bin rather than bin folder. That is the reason why the Sage.Common.LinqBridge.dll still exists after you delete it.
Check the log:
Adding file (d:\a\8\s\xx\xxx\xxx\xxx\obj\Release\Package\PackageTmp\bin\Sage.Common.LinqBridge.dll)
And you could not delete that file in the .zip by the delete task.
To resolve this issue, you could set Copy Local to False for that dll file.
Update2:
After talk with mbharanidharan88, found the reason for this issue is that not use correct syntax in the contents in the delete task.
To delete the file only in the bin folder, we could use the following syntax:
**\bin\Sage.Common.LinqBridge.dll
Hope this helps.

Setup azure-pipelines.yml "Directory '/home/vsts/work/1/a' is empty." with ASP.NET Core

I seriously need help to create my yml build file because I cannot find any good tutorial, sample or other king of help anywhere. I always get similar error: See the warning, it seems my build artifact is always empty. All step are succes but I cannot deploy because my files are not found. Stupid.
##[section]Starting: PublishBuildArtifacts
==============================================================================
Task : Publish Build Artifacts
Description : Publish build artifacts to Azure Pipelines/TFS or a file share
Version : 1.142.2
Author : Microsoft Corporation
Help : [More Information](https://go.microsoft.com/fwlink/?LinkID=708390)
==============================================================================
##[warning]Directory '/home/vsts/work/1/a' is empty. Nothing will be added to build artifact 'drop'.
##[section]Finishing: PublishBuildArtifacts
Here is my pipeline definition
# ASP.NET Core
# Build and test ASP.NET Core projects targeting .NET Core.
# Add steps that run tests, create a NuGet package, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/languages/dotnet-core
trigger:
- master
pool:
vmImage: 'Ubuntu-16.04'
variables:
buildConfiguration: 'Release'
steps:
# - script: dotnet build --configuration $(buildConfiguration)
# displayName: 'dotnet build $(buildConfiguration)'
- task: DotNetCoreInstaller#0
inputs:
version: '2.2.202' # replace this value with the version that you need for your project
- script: dotnet restore
- task: DotNetCoreCLI#2
displayName: Build
inputs:
command: build
projects: '**/*.csproj'
arguments: '--configuration Release' # Update this to match your need
- task: PublishBuildArtifacts#1
inputs:
ArtifactName: 'drop'
Note the 2 line I commented
# - script: dotnet build --configuration $(buildConfiguration)
# displayName: 'dotnet build $(buildConfiguration)'
are in fact part of the default script. I'm not using the default script. I'm following the tutorial https://learn.microsoft.com/en-us/azure/devops/pipelines/languages/dotnet-core?view=azure-devops
Also why I cannot use the templates available for my other projects. Is it because I'm using DevOps repository or because my project has specific settings? I have other project I can manage the build then deployment with graphical template and task. A lot more easier.
Yes, help on yaml pipelines seem a bit scattered and thin on the ground at the moment.
Since your project is AspNetCore, I think what you're missing is the dotnet publish task, after the build task and before the PublishArtifacts:
- task: DotNetCoreCLI#2
inputs:
command: publish
publishWebProjects: True
arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)'
zipAfterPublish: True
But here are steps I have been through trying to resolve frustration with netcore yaml pipelines:
You have already looked through the guide's example tasks & snippets at
Build, test, and deploy .NET Core apps ?
You have noticed that you can click on the build log to see the detailed output of each step in your pipeline?
You have noted that the task DotNetCoreCLI#2 is equivalent to running dotnet <command> on your own desktop so you can to some extent run/debug these tasks locally?
I found Predefined Variables gave some helpful clues. For instance it tells us that the path \agent\_work\1\a is probably the $(Build.ArtifactStagingDirectory) variable, so that helped me in mimicking the pipeline on my local machine.
Logically, your error message tells us that $(Build.ArtifactStagingDirectory) is empty when the pipeline reaches the last step. The dotnetcore example page suggests to me that publish is the task that populates it for a web project. For anything else, I think just the dotnet build task is enough.
Just replace in variables:
**/Dockerfile
…by
$(Build.SourcesDirectory)/Dockerfile
That works for me.

Visual Studio Online build step PackageLocation being ignored

I have a Visual Studio Online build definition that seems to be misbehaving, but I'm not sure if I've just misconfigured something.
There is a build step which is configured as follows:
Type: Visual Studio Build
Solution: **\mysolutionfile.sln
MSBuild Arguments: /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.stagingDirectory)"
The build runs successfully, and the build log shows the msbuild command is executed as follows:
"C:\Program Files (x86)\MSBuild\14.0\bin\msbuild.exe" "C:\a\1\s\Code\mysolutionfile.sln" /nologo /nr:false /dl:CentralLogger,(more removed for brevity) /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="C:\a\1\a" /p:platform="any cpu" /p:configuration="release" /p:VisualStudioVersion="14.0" /p:_MSDeployUserAgent="VSTS_6efdabeb-1c75-43a7-96b2-f40e19a68a35_build_14_122"
As you can see, the package location is correctly set: /p:PackageLocation="C:\a\1\a"
However, later in the build log, the package step shows this log entry:
2017-01-20T05:07:30.9771422Z Executing command ["C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -source:manifest='C:\Users\buildguest\AppData\Local\Temp\PublishTemp\obj\mysolution55\SourceManifest.xml' -dest:package='C:\a\1\s\Code\mysolutionfile\bin\Release\MSDeployPackage\mysolutionfile.zip' -verb:sync -replace:match='C:\\Users\\buildguest\\AppData\\Local\\Temp\\PublishTemp\\mysolutionfile55\\',replace='website\' -retryAttempts:20 -disablerule:BackupRule]
As you can see, in this case the package is being sent to -dest:package='C:\a\1\s\Code\mysolutionfile\bin\Release\MSDeployPackage\mysolutionfile.zip' - and this is indeed where the zip file ends up.
As far as I can tell, this looks wrong. I want to have the packaged application binaries and files end up in the staging directory, but msbuild is overriding me somewhere and putting them into the source checkout folder.
In case it's relevant, the solution contains two projects: an ASP.NET Core web app that is targeting the full .NET Framework; and a portable class library.
Am I doing something wrong in the build configuration?
I reproduced your issue in my TFS Environment and I got the same result with. The package under the "C:\a\1\s" folder not "C:\a\1\a'.
As a workaround, you could add a Copy files step to copy the package from the source folder to $(build.stagingDirectory) path.
I guess that it did not work as you expected because the variable name should be Build.ArtifactStagingDirectory instead of build.stagingDirectory
Example:
- task: VSBuild#1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:Configuration=Release /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(Build.ArtifactStagingDirectory)"'
#msbuildArgs: '/T:"MyProject1" /p:OutDir=$(Build.ArtifactStagingDirectory) /nowarn:FS0049'
- task: PublishBuildArtifacts#1
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: MyWebSiteArtefactZIP
There is also another way to Deploy:
If you have created a Publish Profile (you can use Visual Studio for that),
it is also possible to Publish directly from MSBuild, you can put the Web App username/password in the Azure DevOps Pipeline variables and use them:
- task: VSBuild#1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:Configuration=Release /P:DeployOnBuild=true /P:PublishProfile="MyPublishProfile.pubxml" /P:Username=$(username);Password=$(password)'

Visual Studio Team Services Continuous Integration: NuGet Restore Task Failed

I am using Continuous Integration feature in Team Services (was Visual Studio Online). My build definition targets a specific project in a solution (not the whole solution), which is ClientUI MVC website.
The solution contains three projects:
ClientUI
AdminUI
Client Services
The Build Definition for ClientUI Project:
Repository:
Nuget Installer Step:
I have tried different params but not working.
Visual Studio Build
Before trying to target the a single project, my build definition was targeting the whole solution with the following parameters:
NuGet Installer -> Path to Solution: **\*.sln
Visual Studio Build -> Solution: **\*.sln ; MSBuild Arguments: /p:outdir=$(build.artifactstagingdirectory)
It was working. However now, it generates this error in the Nugget Restore Task:
2016-04-22T21:07:00.6716725Z Set workingFolder to default: C:\LR\MMS\Services\Mms\TaskAgentProvisioner\Tools\agents\1.98.1\tasks\NuGetInstaller\0.1.25
2016-04-22T21:07:00.8163908Z Executing the powershell script: C:\LR\MMS\Services\Mms\TaskAgentProvisioner\Tools\agents\1.98.1\tasks\NuGetInstaller\0.1.25\NuGetInstaller.ps1
2016-04-22T21:07:01.5283529Z ##[error]Cannot find path 'C:\a\1\s\packages.config' because it does not exist.
2016-04-22T21:07:01.5439897Z C:\LR\MMS\Services\Mms\TaskAgentProvisioner\Tools\agents\1.98.1\agent\worker\tools\NuGet.exe restore "C:\a\1\s\packages.config" -NonInteractive
2016-04-22T21:07:03.0441507Z MSBuild auto-detection: using msbuild version '14.0' from 'C:\Program Files (x86)\MSBuild\14.0\bin'.
2016-04-22T21:07:03.0597010Z ##[error]Cannot determine the packages folder to restore NuGet packages. Please specify either -PackagesDirectory or -SolutionDirectory.
2016-04-22T21:07:03.0909881Z ##[error]Unexpected exit code 1 returned from tool NuGet.exe
Try setting "Installation type" to "Install" for "Nuget Installer" task since you are using "packages.config" to install the packages.
For anyone curious, the source of the error about "Please specify either -PackagesDirectory or -SolutionDirectory" is that the build process is trying to issue a command similar to this:
C:\hostedtoolcache\windows\NuGet\4.4.1\x64\nuget.exe restore D:\a\1\s\MyProject\packages.config -PackagesDirectory packages -Verbosity Detailed -NonInteractive
The below screenshots should help if you want to build a project (rather than the solution) and your nuget "packages" folder is at the solution-level.
Additionally, you may need to specify this as the "MSBuild Argument" in the build task of your project: /p:SolutionDir="/"
I had the same thing sorted it out by changing the mapping - go to Repository tab, I had my mapping to another directory which means the nuget installer could not execute.