I am having trouble configuring an Azure DevOps Dotnet core build process.
I have a simple dotnet core project which I am attempting to build in an Azure DevOps environment.
The project is in a subfolder within my repo, but I cannot figure out how to specify how the Pipeline should find my csproj file. The MSDN documentation suggests that you can specify it but there are no examples and all of my attempts are met with errors.
When building a pipeline with the standard dotnet CLI template, the YAML created is:
# ASP.NET Core
# Build and test ASP.NET Core web applications targeting .NET Core.
# Add steps that run tests, create a NuGet package, deploy, and more:
# https://learn.microsoft.com/vsts/pipelines/languages/dotnet-core
pool:
vmImage: 'Ubuntu 16.04'
variables:
buildConfiguration: 'Release'
steps:
- script: dotnet build --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
However this is met with the error:
MSBUILD : error MSB1003: Specify a project or solution file.
The current working directory does not contain a project or solution file.
The documentation linked above suggests using a "task" based syntax rather than a script, and I assume that in the documentation the inputs are listed in the same order as the examples listed underneath.
If you use the script you specify the csproj file after the build word:
- script: dotnet build myrepo/test/test.csproj --configuration $(buildConfiguration)
The best way to use Azure DevOps Pipeline is to use tasks for the build pipeline, in the Dotnet Core yaml build task you specify the file in the inputs section:
- task: DotNetCoreCLI#2
inputs:
command: 'build'
projects: 'myrepo/test/test.csproj'
Related
I'm trying to test my .NET Core 5.0 projects in my Azure DevOps pipeline. When using a full path to one of my test projects the pipeline will test that single project. When using a pattern to search for all my test projects he can't find one of them.
My project structure is as follows:
backend
DemoProject (with the .sln file)
DemoProject.Application
DemoProject.Application.Test
DemoProject.Persistance
DemoProject.Persistance.Test
DemoProject 2
....
To find a solution I created a simple version of my pipeline template:
- master
pool:
vmImage: ubuntu-latest
steps:
- task: DotNetCoreCLI#2
inputs:
command: 'test'
projects: './backend/DemoProject/DemoProject.Application.Tests/DemoProject.Application.Tests.csproj'
When using the full path (./backend/DemoProject/DemoProject.Application.Tests/DemoProject.Application.Tests.csproj), the pipeline find's the selected project. When using a pattern (./backend/DemoProject/\*\*/\*.Tests.csproj or ./backend/DemoProject/\*\*/DemoProject.Application.Tests.csproj), the pipeline can't find any project.
Does someone knows what the correct pattern is to run all my test projects inside the DemoProject folder?
Try **/*.Test.csproj, I have used it in projects with more complex folder structures without any issues.
- task: DotNetCoreCLI#2
inputs:
command: test
arguments: --configuration Release
projects: '**/*.Test.csproj'
workingDirectory: './backend/DemoProject/'
Im trying to pack a web api i made in .net core 3.1 with Azure Pipeline.
- task: DotNetCoreCLI#2
displayName: Package NuGet
inputs:
command: 'pack'
projects: '**/*.csproj'
arguments: '--configuration $(BuildConfiguration)'
outputDir: '$(Build.ArtifactStagingDirectory)/packages'
Thats the task i used, i found it from another post on stack overflow.
My only issue with that is that it gives a number of .nupkg files, instead of one, and that the web api packages doesn't have the dependencies dll.
Also i created a .nuspec file, but i don't seem to manage to use it correctly with Azure Pipeline
I've tried what's explained here : https://learn.microsoft.com/fr-fr/nuget/reference/msbuild-targets#packing-using-a-nuspec
or just by targeting the .nuspec file like it is explained on the tooltipe of pipeline
If anybody could put me on the right path that would be greatly appreciated :)
EDIT:
I want to pack everything in a nupkg to then deploy it for an IIS site.
This is my nuspec file :
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>WebAPI</id>
<version>1.0.0</version>
<authors>Kevin Pinero</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>WebAPI</description>
</metadata>
<files>
<file src=".\bin\Release\*\*.dll" target="lib" />
<file src=".\bin\Release\*\*.exe" target="lib" />
<file src=".\bin\Release\*\*.json" target="lib" />
<!-- <file src=".\bin\Release\*\Properties\*.json" target="lib" /> -->
<file src=".\bin\Release\*\*.pdb" target="lib" />
<file src=".\bin\Release\*\*.config" target="lib" />
</files>
</package>
And this the error i get on the pipeline :
error MSB4068: The element is unrecognized, or not supported
in this context.
Using this task :
- task: DotNetCoreCLI#2
inputs:
command: 'pack'
packagesToPack: '**/*API.nuspec'
nobuild: true
versioningScheme: 'off'
I know on microsoft website I could potentially use this command too
dotnet pack ~/projects/app1/project.csproj -p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget
But i'm not sure how to translate it in AZ pipeline ...
EDIT Solution adopted:
I've decide to resolve my issues this way :
- task: DotNetCoreCLI#2
displayName: Build at solution level
inputs:
command: 'build'
projects: $(solution)
arguments: '--no-restore --configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Execute tests
inputs:
command: 'test'
projects: $(testProjects)
arguments: '--no-build --configuration $(buildConfiguration)'
- task: DotNetCoreCLI#2
displayName: Pack project
inputs:
command: publish
projects: '**/projectName.csproj'
publishWebProjects: False
arguments: '--no-build --configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)
zipAfterPublish: False
- task: PublishBuildArtifacts#1
displayName: Publish
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'artefact name'
I would recommend to use the Azure DevOps online pipeline editor. It is great to use and get up to speed (auto-completion, syntaxic review, direct commit/push).
What you try to achieve can be done with the steps:
dotnet build
dotnet pack -> specify the right projects to be packed here
- task: DotNetCoreCLI#2
displayName: 'Create packed NuGet files'
inputs:
command: 'pack'
packagesToPack: '**/*Api.csproj;!**/*Tests.csproj'
versioningScheme: 'off'
nuget push
No need for a nuspec file as long as you add some fields in your csproj.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<AssemblyName>Withywoods.Selenium</AssemblyName>
<RootNamespace>Withywoods.Selenium</RootNamespace>
<ProjectGuid>{08D9DDB8-BF5B-4E45-8E0C-D9AC85ABF020}</ProjectGuid>
<Authors>devprofr</Authors>
<Description>Library to ease the use of Selenium web driver and provide testing best practices.</Description>
<RepositoryUrl>https://github.com/devpro/withywoods</RepositoryUrl>
<PackageProjectUrl>https://github.com/devpro/withywoods</PackageProjectUrl>
</PropertyGroup>
I have a short example here if you want: pkg.yml
.NET Core and Azure DevOps is a great combination, feel free to comment if you have any issues!
(On my side, I pack library projects but not Api, I do dotnet publish on Api to use them as artifact in release pipelines.)
My only issue with that is that it gives a number of .nupkg files,
instead of one, and that the web api packages doesn't have the
dependencies dll.
I assume you have more than one projects in same solution. Let's call the Web Api project A, other projects B, C and D...
1.So if you only want to pack A into nuget package, instead of using projects: '**/*.csproj', we can use something like projects: '**/A.csproj'. Then it won't pack a number of nuget packages any more.
2.For the dependencies dll, I think you mean the project references like Josh Gust said above. For this, it's still one open issue about dotnet pack command. You can track that issue there to get notifications if there's any update.
For now, we have to make changes to A.csproj to use msbuild magics as workaround. You can try Martin's or zvirja's workarounds there. In my opinion, they both helps for your issue.
Hope all above helps :)
Update1:
For your edit, if you want to translate it in AZ pipeline, you can use the custom command to call the pack. Something like this:
- task: DotNetCoreCLI#2
displayName: 'dotnet custom'
inputs:
command: custom
projects: '**/ProjectName.csproj'
custom: pack
arguments: '-p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget'
You can check the log to confirm it actually ran the command: "C:\Program Files\dotnet\dotnet.exe" pack D:\a\1\s\xxx\xxx.csproj -p:NuspecFile=~/projects/app1/project.nuspec -p:NuspecBasePath=~/projects/app1/nuget. Hope that's what you need.
And I'm not certainly sure that we can use ~ in that command, but if it works locally, then you can translate it in Azure Devops Pipeline using my way...
UPDATE
Because you are trying to package a Web API project for delivery to IIS, you should stop trying to use nuget as that mechanism, and instead use the dotnet publish command. If you want to continue to use the DotNetCoreCLI#2 task (as opposed to using the script shortcut to call the dotnet cli directly), then I would point you to the documentation to Build, Test and Deploy .Net Core Apps.
This documentation is not written specifically for Web API projects, but is a set of generic guidelines for operating with .Net Core Apps is Azure DevOps Pipelines. An example is quoted below (emphasis mine):
After you've built and tested your app (not web api specifically), you can upload the build output to Azure Pipelines or TFS, create and publish a NuGet package, or package the build output into a .zip file to be deployed to a web application.
When you read in the Package and Deliver your Code section that publish to a NuGet feed is a valid option for delivering code, it is. However this method of delivery should be used for library type deliverables. The dotnet publish command is what is designed to package a web api project and all its dependencies into a .zip (or folder if you specify that option) in preparation for Web Deploy commands against an IIS instance.
Original Answer
Without getting into the details of why you want to create a .nupkg from your API project.
You mention:
My only issue with that is that it gives a number of .nupkg files, instead of one, and that the web api packages doesn't have the dependencies dll
This has been the MO of dotnet pack for a while now as regards project-to-project (P2P) references.
The documentation for dotnet pack states this behavior.
NuGet dependencies of the packed project are added to the .nuspec file, so they're properly resolved when the package is installed. Project-to-project references aren't packaged inside the project. Currently, you must have a package per project if you have project-to-project dependencies.
If you want to have more control over the files that are included in your .nupkg then you will want to author a .nuspec file manually and provide it to the dotnet pack command as indicated in the last Example on the documentation page.
Using the Azure DevOps task for the dotnet core cli DotNetCoreCLI#2 should allow you to simply put the path to the .nuspec file in the input. More information will be necessary in your question if this isn't working for you.
I'm trying to build and pack a class library into a NuGet using .NET Core 3.1. It all build fine on my dev machine, but the Azure pipeline build fails during the DotNetCoreCLI pack command. I was able to get the build working on after installing .NET Core 3.1 on the build machine using the UseDotNet. Build and tests run fine, so I believe the 3.1 version is installed correctly.
When I add the pack command, the step always fails. Here is the command I'm using:
- task: DotNetCoreCLI#2
displayName: Package NuGet
inputs:
command: 'pack'
projects: '**/*.csproj'
arguments: '--configuration $(BuildConfiguration)'
outputDir: '$(Build.ArtifactStagingDirectory)/packages'
I get the following error during this step:
/opt/hostedtoolcache/dotnet/sdk/3.1.101/Sdks/NuGet.Build.Tasks.Pack/build/NuGet.Build.Tasks.Pack.targets(198,5):
error NU5026: The file
'/home/vsts/work/1/s/ClassLib31/bin/Debug/netcoreapp3.1/ClassLib31.dll'
to be packed was not found on disk.
[/home/vsts/work/1/s/ClassLib31/ClassLib31.csproj]
Notice the path above is looking bin Debug folder, but this is a Release build. All of the tasks are using the same BuildConfiguration variable, but in this task it appears to be looking for the dll in the Debug folder. Any ideas why?
Additional notes:
- This build script works fine for .NET Core 3.0 projects. I tried switching the library to target 3.0 and removed the 3.1 installation step. Pack works as expected.
- This build script works when I build the Debug version of the library (as you'd expect, since the task is looking in that bin folder).
DotNetCoreCLI#2 Pack command does not support arguments argument.
Arguments to the selected command. For example, build configuration,
output folder, runtime. The arguments depend on the command selected
Note: This input only currently accepts arguments for build, publish,
run, test, custom. If you would like to add arguments for a command
not listed, use custom.
You may use arguments argument for build command and configuration argument for pack command:
- task: DotNetCoreCLI#2
displayName: Build
inputs:
command: 'build'
arguments: '--configuration Release'
...
- task: DotNetCoreCLI#2
displayName: Pack
inputs:
command: 'pack'
configuration: 'Release'
...
There is another workaround, but note that in this case packagesToPack argument does not work:
# command: 'pack'
command: custom
custom: pack
arguments: '--configuration Release'
After a little more time debugging the build pipeline, I discovered that I had mismatched case the BuildConfiguration variable in a couple of places, which caused this to fail in the pack command. I discovered this while combing through the logs for each step.
It seems that if the case mismatch is in earlier commands (like build and test) they default to the release build. But for the pack command it seems to default to look in the debug bin folder. Once I discovered this and cleaned up the script, it works fine now .NET Core 3.1 builds.
I have a simple solution that have two projects in it and I want it go through the azure build pipeline. One project is pure class files that will get build a DLL but that code is not the GIT repo in the same folder. And the other project is ASP.NET project and I have configured that in the pipeline. When I am trying to build the project it is giving me an error as below:
MSBUILD : error MSB1011: Specify which project or solution file to use
because this folder contains more than one project or solution file.
[error]Cmd.exe exited with code '1'.
Yaml File
# 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:
name: 'buildserver'
variables:
buildConfiguration: 'Release'
steps:
- script: dotnet build --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
The error is asking you to identify the .sln or .csproj (or other proj type) file b/c dotnet doesn't know what you want it to do.
I tend to use variables for this kind of thing because I'm often using the solution name in other tasks.
example:
trigger:
- master
pool:
name: 'buildserver'
variables:
buildConfiguration: 'Release'
slnName: 'mySol'
solution: 'some/dir/$(slnName).sln'
steps:
- script: dotnet build $(solution) --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
.csproj example:
With a repository (and solution) structure as follows:
(this is the part of your question that remains unclear)
myRepo
|--.git
|--src
|--proj1
| |--proj1.csproj
|
|--proj2
| |--proj2.csproj
|
|--mySol.sln
You would simply call out the .csproj file you want the pipeline to build.
trigger:
- master
pool:
name: 'buildserver'
variables:
buildConfiguration: 'Release'
projName: 'proj1'
project: 'src/$(projName)/$(projName).csproj'
steps:
- script: dotnet build $(project) --configuration $(buildConfiguration)
displayName: 'dotnet build $(buildConfiguration)'
With the above examples you shouldn't need to specify the .sln or .csproj as each potential build target lives in its own directory, and the dotnet cli searches from $pwd if you don't give it a value. Therefore, if your pipeline is working in the root of the repo (default behavior), dotnet should find the .sln file first and build it.
However
If your directory structure looks like the following, then you would need to specify:
myRepo
|--.git
|--src
|--proj1.csproj
|--class1.cs
|--class2.cs
|--proj2
| |--proj2.csproj
| |--class1.cs
|
|--mySol.sln
In the above dotnet doesn't know whether you want to build mySol.sln or proj1.csproj, so indicating the file to build should solve your problem, but I might suggest that you restructure your repository.
If proj2 doesn't make its home in myRepo
And is a dependency of proj1 then you will need to do some other acrobatics (ie: manual git repo clone) in the pipeline to get that project and it's files where they need to be. If this is the case, I would strongly suggest you treat proj2 as a completely independent product and deliver it to those projects (proj1) that depend upon it via NuGet or other package delivery method.
I have created an application using dotnet core. I am building it as a self-contained package. I am attempting to publish it to an Azure artifact server using the pipeline UI. I have been able to successfully build the self-contained package, and have been able to successfully publish it to the drop. I have not been able to figure out how to get the NuGet pack command (and subsequent Nuget push) to pick up the self-contained package to place as a downloadable package on the artifact server.
Here is the YAML for my publish task:
steps:
- task: DotNetCoreCLI#2
displayName: 'dotnet publish'
inputs:
command: publish
publishWebProjects: false
projects: '**/TelemetryReceiver.csproj'
arguments: '-c release -r win-x64 --self-contained true'
Here is the YAML for the task that copies to build staging:
Your build pipeline references the ‘BuildConfiguration’ variable, which you’ve selected to be settable at queue time. Create or edit the build pipeline for this YAML file, define the variable on the Variables tab, and then select the option to make it settable at queue time. See https://go.microsoft.com/fwlink/?linkid=865971
steps:
- task: CopyFiles#2
displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
inputs:
SourceFolder: '$(build.sourcesdirectory)'
Contents: '**\bin\$(BuildConfiguration)\**'
TargetFolder: '$(build.artifactstagingdirectory)'
Here is the YAML for publish:
steps:
- task: PublishBuildArtifacts#1
displayName: 'Publish Artifact: drop'
inputs:
PathtoPublish: '$(build.artifactstagingdirectory)\src\TelemetryReceiver\bin\Release\netcoreapp2.2\win-x64'
And here is the YAML for the NuGet pack:
steps:
- task: NuGetCommand#2
displayName: 'NuGet pack'
inputs:
command: pack
packagesToPack: src/telemetryreceiver/telemetryreceiver.csproj
versioningScheme: byPrereleaseNumber
On the copy step, the logs indicate the full self-contained package is indeed being copied to "\src\TelemetryReceiver\bin\Release\netcoreapp2.2\win-x64". But one the final package is downloaded from the artifact server, it is only picking up the contents of the "netcoreapp2.2" directory.
I am confused, of course, about how the "dotnet publish" and "NuGet pack" tasks are supposed to relate. It seems as if both independently evaluate the .csproj file and that is it.
How to publish self-contained dotnet core package via pipeline UI to azure artifacts?
You may misunderstand the task dotnet publish, which is not used to publish the nuget package. It used to create a .zip file archive that's ready for publishing to a web app:
Check the document Deploy a web app for some more details.
As test, you can view the content of that .zip:
To publish self-contained dotnet core package via pipeline UI to azure artifacts, you just need use the Copy task and PublishBuildArtifacts task.
The reason why it only pick up the contents of the "netcoreapp2.2" directory, that because you are not the correct syntax in the Contents in the copy task, it should be specify to the .nupkg:
Contents: '**\bin\$(BuildConfiguration)\**\*.nupkg'
Then, in the artifacts:
Alternatively, we could specify the package folder to $(Build.ArtifactStagingDirectory) in the nuget pack task:
In this case, we do not need the copy task to copy package to the ArtifactStagingDirectory, just use task PublishBuildArtifacts.
Hope this helps.