Can I use VSBuild#1 yaml task to restore multiple projects? - azure-devops

I need to restore 3 projects (csproj) using VSBuild yaml task. I know that I can do it if I add 3 yaml tasks, but I wonder if is there a way to restore them all using just one task.
I already tried like this:
- task: VSBuild#1
displayName: 'Restore projects'
inputs:
solution: "'**/Project1.csproj';'**/Project2.csproj'"
msbuildArgs: '/t:Restore'
vsVersion: $(VSVersion)
platform: '$(BuildPlatform)'
configuration: '$(Configuration)'
,and I don't have syntax errors but the pipeline fails with this error: "Solution not found using search pattern..."

Usually, you specify solution file(s) to build (e.g. *.sln) rather than individual projects. So if it's possible to provide a solution file name that includes those 3 projects you need, that would be the best approach.
If that doesn't fit your case, you can use wildcards to provide a mask that fits all 3 projects, for example, **/Project*.csproj.
As the last option, you can try to switch to the MSBuild task instead. In fact, the docs say that:
In some cases you might need to use the MSBuild task. For example, you should use it if you are building code projects apart from a solution.

VSBuild task cannot recognize the multiple projects in this format "'**/Project1.csproj';'**/Project2.csproj'". You can use the wildcards **/Project*.csproj to map your projects.
- task: VSBuild#1
displayName: 'Restore projects'
inputs:
solution: '**/Project*.csproj'
msbuildArgs: '/t:Restore'
If your projects are dotnet core projects. You can use the DotNetCoreCLI task, which support multiple lines input:
steps:
- task: DotNetCoreCLI#2
displayName: 'dotnet restore'
inputs:
command: restore
projects: |
**/Project1.csproj
**/Project2.csproj
**/Project3.csproj

Related

VSBuild Fails with Error MSB4057 When Building with Azure Pipelines ('The target "<project_name>" does not exist in the project')

I am trying to run the VSBuild#1 task in an Azure Pipeline and every time it fails with the same error - "The target "<project_name>" does not exist in the project". I've searched for every answer to this question and none have worked for me. The exact yaml I'm running is
- task: VSBuild#1
displayName: 'Build Project1 and Project2'
inputs:
solution: '$(solution)'
msbuildArgs: '/t:Folder\Project1:Rebuild;Folder\Project2:Rebuild'
clean: true
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
The directory looks like 'Repo\Folder\Project1\Project1.csproj' and 'Repo\Folder\Project2\Project2.csproj' and the VSBuild version is 1.199.
You can run
set MSBuildEmitSolution=1
msbuild All.sln /t:<project_name>
Then search in the generated All.sln.metaproj file the exact target names () of all projects you want to build. After that you can build projects:
msbuild All.sln /t:"<project_name>" /p:Configuration=Release /p:Platform=x64

How to specify project to build in Azure DevOps VSBuild task?

I have this yaml pipeline in Azure DevOps:
variables:
solution: 'fph.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- xxxx
- task: VSBuild#1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /t:FPH_Api\FPH_Api_csproj;Rebuild'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
The solution contain multiple projects and I am hoping that by providing DesktopBuildPackageLocation parameter and target parameter FPH_Api\FPH_Api_csproj;Rebuild, VSBuild will rebuild my web api project (so will rebuild other referenced projects as well) and then automatically zip the build into webapp.zip.
However, I got this error:
FPH_Api\FPH_Api_csproj" does not exist in the project.
I replaced the dots in FPH.API\FPH.api.csproj with underscores as dot is a forbidden character and tried several combinations like FPH_Api\FPH_Api or FPH_Api, but got the same error message.
Detail error shows this:
Project "D:\a\1\s\fph.sln" (1) is building "D:\a\1\s\FPH.Api\FPH.Api.csproj" (2) on node 1 (FPH_Api\FPH_Api_csproj target(s)).
D:\a\1\s\FPH.Api\FPH.Api.csproj : error MSB4057: The target "FPH_Api\FPH_Api_csproj" does not exist in the project.
Done Building Project "D:\a\1\s\FPH.Api\FPH.Api.csproj" (FPH_Api\FPH_Api_csproj target(s)) -- FAILED.
Seems the way I am doing things is not correct. So is it possible to use the VSBuild task to build a project in a solution and automatically zip the output?
I could reproduce your issue in my pipeline.
To solve this issue, you could define the target to folder level instead of csproj file level.
For example:
File structure:(csproj file is under Sample.WebAPI folder)
argument: /t:Sample_WebApi:Rebuild
- task: VSBuild#1
displayName: 'Build solution'
inputs:
solution: '$(Parameters.solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactstagingdirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site" /t:Sample_WebApi:Rebuild'
platform: '$(BuildPlatform)'
configuration: '$(BuildConfiguration)'
For more info, you could refer to this doc about How to: Build specific targets in solutions by using MSBuild.exe
I realise that this is an old question but I have just been through similar pain trying to build a specific project from my solution using the msbuild targets argument. The answer was buried in this stack overflow thread specify project file of a solution using msbuild but it still took me a while to work out.
The msbuild /t parameter does not want file path and file name. Instead it requires the solution folder structure and the name of the project.
Optional: solution folder structure
Project name
wrapped in double quotes if there are any spaces in the parameter
Periods replaced with underscores.
For example if I have added FPH.Api project within a second level solution folder (e.g. Top Level > Second Level > FPH.Api) then I will see something like this in the .SLN file
Project("{guid}") = "Top Level", "Top Level", "{guid}"
EndProject
Project("{guid}") = "Second Level", "Second Level", "{guid}"
EndProject
Project("{guid}") = "FPH.Api", "FPH.Api\FPH.Api.csproj", "{guid}"
EndProject
In this case you would construct the /t parameter value as:
/t:"Top Level\Second Level\FPH_Api"
I hope that is helpful.

Azure Pipeline - Build one project from solution with project dependencies

I have a solution that has a few projects.
App.Client.Website
App.Client.WindowsService
App.Client.Database
App.Client.Connectors
App.Shared
The App.Client.Database and App.Client.Connectors are both dependencies of App.Client.Website and App.Client.WindowsService, and App.Shared is a dependency of all the projects.
I am wanting to create 2 pipelines: One for the website and one for the windows service.
The issue that I have is that when I set my solution to be App.Client.Website/*.csproj, it can't find any of my project references to build - which makes a lot of sense to me, but I would obviously like to have it build my project references as well.
I tried solving this by creating pipelines for each of the dependency projects that would pack a nuget package and then I would reference that nuget packages from the feed in my website and window service projects, but this stopped me from being able to debug the code and make changes in those project on the fly.
DevOps is something that I am only just starting to pick up. I have gotten to the point where I am needing to add build numbers to my website application and wanting to stop manually incrementing patch numbers. I am using YAML instead of the Classic pipeline builder.
Any and all help is appreciated.
YAML
Here is the YAML that I am using. It is just the basic YAML with the solution targeting my Website project.
# ASP.NET
# Build and test ASP.NET projects.
# Add steps that publish symbols, save build artifacts, deploy, and more:
# https://learn.microsoft.com/azure/devops/pipelines/apps/aspnet/build-aspnet-4
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.Client.Website/*.csproj'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller#1
- task: NuGetCommand#2
inputs:
command: 'restore'
restoreSolution: '$(solution)'
feedsToUse: 'config'
nugetConfigPath: 'Pipelines/nuget.config'
externalFeedCredentials: 'External Feed'
- task: VSBuild#1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactStagingDirectory)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: PublishBuildArtifacts#1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'drop'
publishLocation: 'Container'
The repo folder structure has the project folders at the root of repo.
My project references in my Website cs project file are as follows:
<ItemGroup>
<ProjectReference Include="..\App.Client.Database\App.Client.Database.csproj" />
<ProjectReference Include="..\App.Client.Connectors\App.Client.Connectors.csproj" />
<ProjectReference Include="..\App.Shared\App.Shared.csproj" />
</ItemGroup>
Here is an error from the build task:
##[error]C:\Program Files\dotnet\sdk\3.1.403\Sdks\Microsoft.NET.Sdk\targets\Microsoft.PackageDependencyResolution.targets(241,5): Error NETSDK1004: Assets file 'D:\a\1\s\App.Shared\obj\project.assets.json' not found. Run a NuGet package restore to generate this file.
The issue is related to the NuGet Restore task, We could try to restore the .sln file to restore all NuGet packages, and then build the .csproj file. It should work.

Specify framework/platform in Azure pipeline yml

I want to tell Azure to run tests against the framework and platform actually used by my test project. According to Microsoft,
Tests that target the .NET core framework can be executed by specifying the appropriate target framework value.
But how do I do that?
Additionally, the log output says there is an issue of different platforms. I'm not sure how to address that either. I've tried putting a platform into my yml, but it doesn't help.
Here is my current yml:
- job: Test
dependsOn: SetBuildName
pool:
vmImage: 'windows-2019'
variables:
solution: '**/MyTestSolution.sln'
buildPlatform: 'x86|x64|ARM'
buildConfiguration: 'Release'
appxStagingDir: '$(build.artifactStagingDirectory)\AppxPackages\\'
steps:
- task: NuGetToolInstaller#1
inputs:
versionSpec: '5.4.0'
- task: NuGetCommand#2
inputs:
restoreSolution: '$(solution)'
- task: VersionAPPX#2
inputs:
Path: '$(Build.SourcesDirectory)'
VersionNumber: '$(versionNumber)'
InjectVersion: true
OutputVersion: 'OutputedVersion'
- task: VSBuild#1
inputs:
platform: 'x86' #Changing this to AnyCPU had no effect.
solution: '$(solution)'
configuration: '$(buildConfiguration)'
msbuildArgs: '/t:Restore'
- task: VSBuild#1
inputs:
platform: 'x86'
solution: '$(solution)'
configuration: '$(buildConfiguration)'
msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)"
/p:AppxPackageDir="$(appxStagingDir)"
/p:AppxBundle=Always
/p:UapAppxPackageBuildMode=Sideload
/p:AppxPackageSigningEnabled=true
/p:VersionPrefix="$(versionNumber)"
/p:VersionSuffix="$(version.SpecialBuild)"
/p:SourceRevisionId="$(Build.SourceVersion)"'
And here is an excerpt from the log:
2020-03-19T12:28:57.5842598Z Test run will use DLL(s) built for framework .NETFramework,Version=v4.0 and platform X86. Following DLL(s) do not match framework/platform settings.
2020-03-19T12:28:57.5843802Z MyProject.Test.dll is built for Framework .NETCoreApp,Version=v3.1 and Platform AnyCPU.
The best solution would be to tell it to use whatever the project built against. But if that isn't possible, I'd settle for a way to specify NETCoreApp 3.1 and AnyCPU.
Tests that target the .NET core framework can be executed by
specifying the appropriate target framework value.
In VSTest#2 task, there has one argument names otherConsoleOptions. It can pass some additional options to the tool vstest.console.exe, including platform, framwork and etc.
Note: The platfrom argument of task just purely for reporting purposes.
Here is what I am using on my YAML:
- task: VSTest#2
inputs:
testSelector: 'testAssemblies'
testAssemblyVer2: |
**\Release\UnitTestProject1.build.appxrecipe
!**\*TestAdapter.dll
!**\obj\**
searchFolder: '$(System.DefaultWorkingDirectory)'
otherConsoleOptions: '/Platform:x86 /Framework:Framework45'
platform: 'x86|x64'
Just replace the otherConsoleOptions value based on your actual demand like this:
otherConsoleOptions: '/Platform:{platform type: x86/x64/ARM} /Framework:{Framwork version}'
Above method is used for making platform/framwork configuration in yml file.
But there has another way you can use to achieve it: specify platform type and framwork version in your runsetting file.
<RunSettings>
<!-- Configurations that affect the Test Framework -->
<RunConfiguration>
...
...
<TargetPlatform>x86</TargetPlatform>
<TargetFrameworkVersion>Framework40</TargetFrameworkVersion>
....
....
</RunConfiguration>
...
...
</RunSettings>

DotNetCLI#2 pack seems to be ignoring configuration inputs

The below YAML snippet does not seem to work as expected.
I configured it in a pipeline that runs using the windows-latest image and it attempts to restore all of the projects that are in the repo, instead of looking just to the solution file.
Also, it seems to completely ignore the --no-restore flag
- task: DotNetCoreCLI#2
displayName: Package to Staging directory
inputs:
command: pack
configuration: $(BUILD_CONFIGURATION)
projects: 'support-libs.sln'
packDirectory: $(Build.ArtifactStagingDirectory)
nugetConfigPath: 'sf-solution/nuget.config'
arguments: '--no-restore'
verbosityRestore: Minimal
The command that appears on the step logs is:
"C:\Program Files\dotnet\dotnet.exe" pack
d:\a\1\s\sf-solution\SampleProject\SampleProject.csproj --output
d:\a\1\a /p:Configuration=Debug --verbosity Detailed
The above project is not even included in the support-libs SLN file the snippet has configured.
The above project is not even included in the support-libs SLN file the snippet has configured
Not sure why DotNetCLI task pack the project, which is not included in in the support-libs SLN. Since you did not share your project file structure and the build log in your question, I could not give you the directly reason for this issue.
But as workaround, you could specify the specific project file instead of the solution file. Besides, you can also check this task by classic editor:
It state the path to csproj or nuspec file(s) to pack.
For the ignoring configuration inputs problem, there is an option Do Not build, so, you could add this argument to your pack task instead of the argument --no-restore:
- task: DotNetCoreCLI#2
displayName: 'dotnet pack'
inputs:
command: pack
packagesToPack: YourProjectPath&Name.csproj
nobuild: true
Note: Add a DotNet build task before you use this pack task.
Hope this helps.
I was finally able to do what I wanted and to pack all the libraries inside the solution, however I had to use a custom command instead of the pack one:
- task: DotNetCoreCLI#2
displayName: Package to Staging directory
inputs:
command: custom
custom: 'pack'
arguments: 'support-libs.sln -c=$(BUILD_CONFIGURATION) -o $(Build.ArtifactStagingDirectory)'
verbosityRestore: Minimal
verbosityPack: Minimal
feedsToUse: select
vstsFeed: personalnugetfeed
nuGetFeedType: internal
includeNuGetOrg: true
I was also having authorization issues with the internal feed that was in the Nuget configuration and linking to that file, even from a custom command, had the same issues.
Explicitly stating from which feed the restore should be made worked perfectly and I was able to retrieve all the dependencies removing the need to use the --no-restore flag.