I'm working with a handful of Xamarin Forms projects and projects that produce multi-targeted Xamarin packages. I have spent a day wrestling with getting one of the projects to work properly in Azure DevOps and I give up.
When I work with one particular unit test project locally, it sets up this directory structure:
+ ProjectName
+ bin
+ obj
+ ...
+ packages
+ <nuget packages here>
This structure manifests itself in parts of the project file like this:
<Import Project="..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" />
<Import Project="..\..\packages\NUnit.3.12.0\build\NUnit.props" Condition="Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" />
There's another part of the project file that depends on this:
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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 {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\NUnit.3.12.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.12.0\build\NUnit.props'))" />
<Error Condition="!Exists('..\..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.15.1\build\net35\NUnit3TestAdapter.props'))" />
</Target>
When I build this locally, everything is fine. The project builds. The tests pass. When I build this in Azure DevOps, it fails:
(EnsureNuGetPackageBuildImports target) ->
D:\a\1\s\[Redacted].Unit.Tests\[Redacted].Unit.Tests.csproj(97,5): error : 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\NUnit.3.12.0\build\NUnit.props.
So clearly Azure DevOps has a different idea of where the packages folder is created. If I edit the ..\.. to ..\, everything works. This is consistent with a lot of projects. In several of my other projects, all of the .csproj files use ..\ and they have this directory structure:
+ ProjectName
+ bin
+ obj
+ packages
+ ...
I can't find anything in either .csproj that seems to indicate either one is instructing nuget to do anything differently. But it's behaving VERY differently for each one. My only guess is I have some super-hidden local config for the "broken" one that changes the default behavior, and that file's not in source control so DevOps uses the "real" default?
What could be causing this to happen?
Some people asked for the .yml to see how we're restoring packages: I believe this is it:
- task: NuGetToolInstaller#1
displayName: "Install nuget"
inputs:
versionSpec: '4.4.1'
- task: NuGetCommand#2
displayName: 'restore $(solution)'
inputs:
restoreSolution: '$(solution)'
vstsFeed: "$(packageFeedName)"
I'm not the devops guy for the team, but I know a little about the yml. $(solution) is just a path to our solution file, and the package feed name is what it says it is. They seem pretty straightforward to me.
Related
I have a package config file for a project this
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Stylesoft.Common.Dev" version="1.0.1.0" targetFramework="net461" />
</packages>
And the package dll is referenced like this in csproj file
<Reference Include="Stylesoft.Common.Dev, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\..\SharedPackages\Stylesoft.Common.Dev.1.0.1.0\lib\net40\Stylesoft.Common.Dev.dll</HintPath>
</Reference>
Earlier this used to work because nuget used to restore the package in this folder Stylesoft.Common.Dev.1.0.1.0 but I don't know what was changed but now nuget skip the revision number of version, now it creates folder with name Stylesoft.Common.Dev.1.0.1 skipping last zero and so I get compile error, because the project tries to check dll in this path
..\..\..\..\..\SharedPackages\Stylesoft.Common.Dev.1.0.1.0\lib\net40\Stylesoft.Common.Dev.dll
I am not able to figure out what was changed and how to make it restore package in the same folder structure as earlier
Any help would be appreciated!
I was suffering the same problem. The cause will either be that the nuget.exe version has been updated and now downloading packages excluding the revision in the path, or that a change has occurred where the packages are hosted. Not sure which for myself as this happened when migrating source from TFS to Azure DevOps. So the build pipeline is different and the packages are on a new feed.
I feel the best solution is to make the projects in Visual Studio work locally the same way the server build expects them to. So as it is looking for packages in folders excluding the revision number in their name, that's where they should be.
So the fix is to reinstall the packages using the same feed and nuget client. The visual studio package manager should install the packages to the correct location. So you can either ensure that you have the correct versions, or just hope it will be ok and continue with the following:
Delete all of the packages from the packages folder (hopefully all your projects use the same folder otherwise this may be laborious).
Clear your nuget package cache from visual studio (there's a button to do this under Tools -> Options -> Nuget Package Manager)
In visual studio, open the nuget package manager console.
Run 'Update-Package -reinstall'
It may take some time depending on how many packages and projects you have, but this will hopefully ensure your project reference hint paths will match the packages' installed locations.
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 have a .net-core application that works on my machine but when I deploy it on another one, it complains about missing packages and points me to the TheApp.deps.json.
My theory is that on my machine the app looks for packages in some NuGet cache where they were probably installed by the IDE during development because the app's output-dir contains only a couple of internal dlls so the other nuget.org dependecies are definitely missing.
I'm building the app with
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
</PropertyGroup>
and then xcopy it to the other machine.
Question
Is there a way to restore or install the missing packages to the cache on the target machine based on the *.deps.json file?
dotnet build (and the F5/Build function in Visual Studio) simply build the code that you have provided via your source files (i.e cs, fs, vb, etc.).
Whereas dotnet publish (and the Build > Publish function in Visual Studio) does a full package restore, builds your source code, and resolves any external dependencies before moving the output to a specific directory ready for publishing to another machine.
The description on the dotnet publish command documentation states:
dotnet publish compiles the application, reads through its dependencies specified in the project file, and publishes the resulting set of files to a directory. The output includes the following assets:
Intermediate Language (IL) code in an assembly with a dll extension.
.deps.json file that includes all of the dependencies of the project.
.runtime.config.json file that specifies the shared runtime that the application expects, as well as other configuration options for the runtime (for example, garbage collection type).
The application's dependencies, which are copied from the NuGet cache into the output folder.
dotnet build is only really useful for building on your development machine, and when used in conjunction with dotnet run against a project file.
With all dependencies added to the package.
I've tried multiple ways but it looks like I might have to get messy to do it, adding a nuspec file on its own is not sufficient because of the way in which dependencies are resolved.
To put this into perspective If I a package a .net framework project with a nuspec file and in the file point at the relevant output folder (for example bin\release) of a build I get everything I need.
My use case is to run some acceptance tests (out of process) in a CI pipeline. At this point I don't want to be accessing source control.
Take a look at NuGet.Build.Tasks.Pack
You can use a .nuspec file to pack your project if you reference at NuGet.Build.Tasks.Pack. I've done this to roll up multiple projects in my solution into one nuget package.
You can pack with dotnet.exe:
dotnet pack <path to .csproj file> /p:NuspecFile=<path to nuspec file> /p:NuspecProperties=<> /p:NuspecBasePath=<Base path>
Or MSBuild:
msbuild /t:pack <path to .csproj file> /p:NuspecFile=<path to nuspec file> /p:NuspecProperties=<> /p:NuspecBasePath=<Base path>
More details can be found here:
https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#packing-using-a-nuspec
Ok so this is not a particularly unusual use case but with .NET framework nuget packaging there is no ceremony.
So I am deploying a package which has some test assemblies and all of the associated dependencies (assemblies and appsettings files) needed for successful exection by Nunit console runner
The solution we have come up with is use both DotNetCorePublish and OctoPack (As a convenience instead of nuget pack)
So DotNetCorePublish reconciles all 3rd party dependencies in place and creates a folder (named publish by default) with everything needed to execute any tests in there (so this is a Framework dependent deploy I have since learnt)
OctoPack then is configured to point to what we want to package. So, setting this to the relevant folder (using relevant wildcards/globs) pulls in everything we need. A nuspec file is created on the fly which is used to created the Nuget package.
We migrate our project to NET STANDARD, but when the project is compiled many errors appear on the errors list:
Severity Code Description Project File Line Suppression State
Error Build action 'EmbeddedResource' is not supported by one or more of the project's targets. MyApp C:\desenvolvimento\aplicativo\App\MyApp\App.xaml 0
the project runs normally but many of this errors appears...
i am using the latest version of Visual Studio 2015 and Xamarin, all the libs and softwares are up to date.
These are only Intellisense errors. If you just switch your error list filter to Build Only (instead of Build + Intellisense), then you will see that they disappear and your project will continue to build.
If your project is building correctly but these errors persist, this is because Visual Studio keeps a cache of the errors on .suo (Solution User Options) and sometimes these errors are not refreshed as should.
To force refresh close Visual Studio and delete all .suo files (including inside .vs folder). You will loose all state for this project (open files and windows, windows positions etc).
I had this issue and searched online, eventually found this answer https://forums.xamarin.com/discussion/comment/89268/#Comment_89268
It looks like a tag in the older VS solution file is the cause.
As stated in the answer, you can fix the build error by opening up the .csproj file in a text editor, finding the EnsureNuGetPackageBuildImports Target and removing it.
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Xamarin.Forms.1.2.2.6243\build\portable-win+net45+wp80+MonoAndroid10+MonoTouch10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)','..\packages\Xamarin.Forms.1.2.2.6243\build\portable-win+net45+wp80+MonoAndroid10+MonoTouch10\Xamarin.Forms.targets'))" />
</Target>
Loaded solution and all working.