dotnet semantic versioning in a continuous deployment environment - .net-core

I am configuring semantic versioning with GitLab for my dotnet core apps and netstandard 2.0 packages.
After reading quite a bit of opinions, some of them contradictory, this is what is clear to me.
A semantic version should be something like
M.m.P.B-abc123 where
M is major version
m is minor version
P is patch version
B is build version (optional)
-abc123 is suffix (optional) in case I use pre-releases. It must start with letter
So the following package versions would be valid:
1.0.0
1.0.1.20190301123
1.0.1.20190301123-beta
1.0.1-rc1
I have the following gitlab script for my versioning
#Stages
stages:
- ci
- pack
#Global variables
variables:
GITLAB_RUNNER_DOTNET_CORE: mcr.microsoft.com/dotnet/core/sdk:2.2
NUGET_REPOSITORY: $NEXUS_NUGET_REPOSITORY
NUGET_API_KEY: $NEXUS_API_KEY
NUGET_FOLDER_NAME: nupkgs
#Docker image
image: $GITLAB_RUNNER_DOTNET_CORE
#Jobs
ci:
stage: ci
script:
- dotnet restore --no-cache --force
- dotnet build --configuration Release
- dotnet vstest *Tests/bin/Release/**/*Tests.dll
pack-beta-nuget:
stage: pack
script:
- export VERSION_SUFFIX=beta$CI_PIPELINE_ID
- dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME --version-suffix $VERSION_SUFFIX --include-symbols
- dotnet nuget push **/*.nupkg --api-key $NUGET_API_KEY --source $NUGET_REPOSITORY
except:
- master
pack-nuget:
stage: pack
script:
- dotnet restore
- dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME
- dotnet nuget push **/*.nupkg --api-key $NUGET_API_KEY --source $NUGET_REPOSITORY
only:
- master
This generates packages such as:
1.0.0 for master branch (stable or production ready) and 1.0.0-beta1234567 for any other branch.
The problem with my approach is that I have VS solutions with multiple projects, each project will be a nuget package and each one has its own version. Sometimes I modify one project but not the other, therefore in theory I shouldn't need to produce a new artifact of the project that I didn't touch nor a new version, of course.
Right now my nuget repository prevents overwriting packages, so If there is a XXX.YYY 1.0.0 and I generate another XXX.YYY 1.0.0 and push it to the repository, it will throw an error and the pipeline will fail.
I have thought that maybe it's not such a bad idea to generate a new package each time I run the CI/CD pipeline, so I considered introducing the build number and have something like XXX.YYY 1.0.0.12345 and, even if I don't touch anything there, the next time a new package XXX.YYY 1.0.0.123499 would be produced.
Is this a correct approach in a continuous deployment scenario? or should I look for a way to make my script smarter and not to produce a new artifact if there is already one with the same version in my nuget repository?
Assuming it's ok to use build numbers always, how do I make sure that only the build number is retrieved from the pipeline but the M.m.P version numbers remain in my csproj as per the following?
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Whatever</Description>
<VersionPrefix>1.0.1</VersionPrefix>
</PropertyGroup>
</Project>
I would need something like:
dotnet pack *.sln --configuration Release -p:PackageVersion=$FIXED_VERSION.$CI_PIPELINE_ID --output nupkg
but I don't know how to retrieve the <VersionPrefix> content from the csproj through the CLI.
Any advice, good read or solution for my approach assuming it's valid?
Thanks

The problem with my approach is that I have VS solutions with multiple projects, each project will be a nuget package and each one has its own version. Sometimes I modify one project but not the other, therefore in theory I shouldn't need to produce a new artifact of the project that I didn't touch nor a new version, of course.
Since a continuous integration pipeline is unable to determine if your code should be a new minor or major version you will always have to determine which semantic version your package should get. This makes the whole process a lot easier.
The guys from visual studio team services have this to say about it:
Immutability and unique version numbers
In NuGet, a particular package is identified by its name and version number. Once you publish a package at a particular version, you can never change its contents. But when you’re producing a CI package, you can’t know whether it will be version 1.2.3 or just a step along the way towards 1.2.3. You don’t want to burn the 1.2.3 version number on a package that still needs a few bug fixes.
SemVer to the rescue! In addition to Major.Minor.Patch, SemVer provides for a prerelease label. Prerelease labels are a “-” followed by whatever letters and numbers you want. Version 1.0.0-alpha, 1.0.0-beta, and 1.0.0-foo12345 are all prerelease versions of 1.0.0. Even better, SemVer specifies that when you sort by version number, those prerelease versions fit exactly where you’d expect: 0.99.999 < 1.0.0-alpha < 1.0.0 < 1.0.1-beta.
Xavier’s blog post describes “hijacking” the prerelease tag to use for CI. We don’t think it’s hijacking, though. This is exactly what we do on Visual Studio Team Services to create our CI packages. We’ll overcome the paradox by picking a version number, then producing prereleases of that version. Does it matter that we leave a prerelease tag in the version number? For most use cases, not really. If you’re pinning to a specific version number of a dependent package, there will be no impact, and if you use floating version ranges with project.json, it will mean a small change to the version range you specify.
Source: https://devblogs.microsoft.com/devops/versioning-nuget-packages-cd-1/
As stated first you still need to pick a version yourself for you new package. For the process before the actual publishing of the final package (master branch in your case) you can use the pre release tag to include the build number as the pre release tag.
Without doing anything smart this will publish a new package for every pipeline that is run. The people at visual studio team services and I do not think that this is a bad thing but this will be up to everyone's personal taste

I know it's a little bit late, but maybe others in the future also ask this question.
For background: I work in a small company and we started in the NodeJS world with NPM packages. After a while we also started building with .NET Core and we kind of adapted some things from the JavaScript world. A tool we used heavily is Semantic Release. It automates versioning by parsing commit messages. So you (and everyone developing on the project) use a special format for commits with a prefix type like fix, feat, chore and so on, and Semantic Release parses every commit message since the last release and determines the next version number.
Since in JS world you have to only update the package.json file it kinda works out of the box but for .NET there is a little bit more work to do.
We use the Directory.Build.props file to set the version like you would do with package.json (but it would work in a csproj file too).
Now Semantic Release works with plugins and one plugin we wrote can update files with the version number. So we use it to update the verson number in Directory.Build.Props. But instead of the version in the file you could also directly give the version number to the dotnet nuget cli but we found it more convenient to have it in the file.
So here's the flow we use for our (internal) NuGet packages:
configure Semantic Release to update the version number in Directory.Build.props file (before creating the package)
create the nuget package (we have another plugin for that, but you could just use the exec plugin during the prepare stage of SR
publish the nuget package during the publish stage of SR
The CI script would then just a call to npx semantic-release in an environment that has NPM as well as the .NET SDK available (we use container images for that).
Especially for OP's situation it would be a little bit more complicated, since multiple projects exists in one repository and SR is made to work in a single repository since it works with git tags to determine the last version. So I would advise to split it in multiple repositories.
The benefits are:
automation of release whenever there is a new feature/bugfix
automation of version numbers that adhere to Semantic Versioning (and is unopinionated)
automatically generate a Changelog along with every release
depending on the Git Platform you can also create releases (there are plugins for GitHub, GitLab and others)
you can configure SR to create pre-releases in certain branches, for example you can have an alpha or beta or develop branch
you could also add the commit hash to the NuGet package so everyone using it would know exactly what is bundled in it
Semantic Release creates a commit with the updated package.json (you can configure it to also include the updated Directory.Build.props and I would advise to do so)
And all you have to do is to configure it one time and enforce a special Commit Message style (which one is not so important, you can configure SR accordingly).

Related

How to ensure same nuget packages versions will be used during publish and tests?

I have solution with following projects:
Api
Application
Infrastructure
Tests
Api is WebApplication (entry point) and has ProjectReferences to libraries Application and Infrastructure.
Tests is a xunit test project and has ProjectReferences to Api / Application / Infrastructure.
I want consistent package versions both during publishing main (Api) project and during running tests.
I added following properties to Api.csproj:
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(CI)' == 'true'">true</RestoreLockedMode>
And it generated Api/packages.lock.json - and it seems that this file also tracks versions of dependencies of referenced projects.
Here is how I publish application (Api):
RUN dotnet restore ./Api/Api.csproj
RUN dotnet publish Api -c Release -o out --runtime alpine-x64 --self-contained true /p:PublishTrimmed=true
So if CI=true env var is set, then commands above should either restore packages according to package.lock.json or fail.
However before publishing Api I run tests like this:
dotnet test ./Tests/Tests.csproj
My question is how to ensure that exactly same package versions will be used suring testing as in Api/package.lock.json? Because if I add <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> to Tests project then it will have separate Tests/package.lock.json file which may not be same as the one in Api/package.lock.json, right? On the other hand when Tests project references Api project then from what I understand Api/package.lock.json is ignored (when running Tests project)?
Is it possible to have one package.lock.json for solution (same for all projects in solution)?
I feel a bit bad for making this an answer and possibly getting rep votes, when mu88 beat me by 12 hours in the comments to the question, but Central Package Management is the answer. There's also a blog post about it.
Currently, neither Visual Studio, nor dotnet add package support installing or upgrading packages, so you will need to hand edit all the xml (csproj, props) files. But support should be coming in VS 2022 17.4, .NET SDK 6.0.400.

How to ignore dependencies for .NET Core during NuGet packaging?

I have my own NuGet packages located on a disk (local Nuget). I'm trying to not add the same DLL multiple times and get in a scenario like the image attached
I have tried the following code during packing but doesn't work
dotnet pack PathtoSolution\SystemCore.Services.Data --no-dependencies --output "G:\NuGetPackages"
However, during restoration to another project, the dependency comes back.
Is there a way to not include dependencies during the packing process or is ignoring at installation time my only option?
You can add to your PackageReference PrivateAssets="all" - however this has some undesirable effects as well as you won't be able to access the types defined in those assemblies outside of your nuget package. If that's ok with you, it would work.

How to deploy a sample GRPC [client-server] solution in raspberri pi in dotnet core

I am trying to run a simple GRPC client-server code in raspberri Pi running Raspbian os.
Language that i am using -C# dotnet core (2.1)
I downloaded a sample project from here.
This is a dotnet core project . I am able to run it in Windows environment, i am also able to modify .proto file in this code and run successfully.
I published the solution as it is with command
{ dotnet publish -r linux-arm }
When tried running same on Rpi, i am getting exception. Attached screenshot has the details of it.
Any help to get through this would be of great use
tl;dr The problem is the libgrpc_csharp_ext native library which currently does not get compiled and built for the arm7 processor. I've compiled it (on a pi) for arm7 and released a nuget package to bridge the gap until they support it all the way: https://www.nuget.org/packages/libgrpc_csharp_ext.arm7/
I'll update with a link to a blog post when I finish getting the rest of the tooling and template finished I'm working on.
fuller explanation: the Grpc.Core nuget package contains the native libgrpc_csharp_ext library that the dotnet implementation of grpc loads in NativeExtensions.cs then maps with PInvoke in NativeMethods.Generated.cs. Inspecting that package, you'll see a version of that library in each /runtimes/[win, osx, linux]/native folder. Unfortunately, no linux-arm version of the library is included. However, in the code, if the platform is linux, it will try to load the static library using the name as formatted here. Dissect that a little and you'll see that as of right now, any 'linux' platform that isn't '64bit' (which despite the proc on the pi being 64 bit, the distro of linux you're using on there, including raspbian, likely isn't) will look for libgrpc_csharp_ext.x86.so. When you dotnet publish -r linux-arm, you'll see that library there in the build output, but unfortunately, it's the wrong one (I think publish just grabs 'the closest one' when it can't find a specific library in the runtimes folder).
The nuget package I created above is compiled for arm7 - I actually cloned the grpc repo onto a pi and peeled away enough of the /csharp build to just cmake the libgrpc_csharp_ext. The 'trick' the package uses is to put the library in runtimes/linux-arm/native folder within the package, which dotnet core recognizes when publishing and pulls into the build output - but the library is still named libgrpc_csharp_ext.x86.so because of the way NativeMethods.cs formats the library name.

No executable found matching command "dotnet-add"

I just did a fresh install of Fedora 25 (followed by an install of dotnet core 1.1) to explore the possibilities of doing some dotnet core development in an linux environment. On attempting to add my first package I received the following error:
No executable found matching command "dotnet-add"
I have seen some similar errors in other SO posts, but nothing that seems to be helping this issue. I attached some images below of the error, dotnet version info, system path, and dotnet location.
Thanks ahead of any tips!
You have installed a version of the dotnet SDK ("CLI" / dotnet-dev package) of the preview2 time, which is still project.json based. This version of the CLI does not contain the dotnet add set of verbs. These were publicly released with the 1.0.0 version. (at the time of writing, the current version of the SDK / CLI is 1.0.4).
Depending on which instructions you followed to install the components, make sure to update to new versions of the SDK / CLI (e.g. microsoft's install instructions for Fedora).
Note that the version of the SDK / CLI is a different one that the version of the runtime(s) on the machine.
Had the same trouble running VS 2017 Version 15.3.5 found a very helpful article
http://thedatafarm.com/data-access/no-executable-found-matching-command-dotnet-ef/
My Basic problem is the tooling is split into two:
One for CLI: Microsoft.EntityFrameworkCore.Tools.DotNet
One for Powershell: Microsoft.EntityFrameworkCore.Tools

Automatically update dependencies declared by local Meteor packages

It is rather tedious when trying to get dependencies of local Meteor packages up-to-date.
Currently, they are specified in package.js like and I have to check for latest version of each dependency used and update manually.
E.g.
api.use([
'alanning:roles#1.2.14',
'aldeed:simple-schema#1.5.3',
'aldeed:collection2#2.8.0',
'iron:router#1.0.12',
'useraccounts:iron-routing#1.12.4'
]);
Can meteor-tool do this or is there a better way to update packages' dependencies, especially useful when you have multiple local packages in a project.
There is no real value in bumping the dependency version in package.js, as I mentioned in my comment. It could lead to the counter effect and break version resolution.
The expectation is to mention the minimal compatible version (with the same major version number). When your local package is updated, its .versions file is updated as well, which may hint the build system which version of the dependency is the preferred one to use (the one that your package was built with).
The closest thing that I can give as an answer is this quote of David Greenspan* taken from the Meteor forums:
We have made some small improvements to meteor update over time, but
we don't have a way for a package to ask for one of its dependencies
to be upgraded more aggressively. meteor update with no arguments will
take patch updates to indirect dependencies, but not minor versions. I
recently improved the messages that meteor update prints, so in the
next release, it should tell you if an indirect dependency is not at
the latest version after it runs (rather than printing the very wrong
message "All packages are at their latest compatible versions").
If you bump the minor version of a package, I think the expectation at
the moment is that you will republish the packages that depend on it
if you want their users to get the new version (after running the
tests to make sure all is well).
So, when the author of a package you depend on releases a new:
patch version: no need for you to do anything. The new version should be used automatically.
minor version: check that everything works and release a new patch version, as to acknowledge the new version.
major version: things are expected to break. Make the required changes and release according to semver rules.
I would not count on things behaving as they do right now, as the packaging system undergoes pretty significant rework in order to be more compatible with NPM (including the ability to directly require NPM packages from Meteor apps and packages), expected to be included in v1.3.
* (actually, Sacha Greif posted the quote).
This is from the docs:
In general, you must specify a package's version (e.g.,
'accounts#1.0.0' to use version 1.0.0 or a higher compatible version
(ex: 1.0.1, 1.5.0, etc.) of the accounts package). If you are sourcing
core packages from a Meteor release with versionsFrom, you may leave
off version names for core packages. You may also specify constraints,
such as my:forms#=1.0.0 (this package demands my:forms at 1.0.0
exactly), or my:forms#1.0.0 || =2.0.1 (my:forms at 1.x.y, or exactly
2.0.1).
So the answer is, it will not update your package.js script but it will download the latest compatible versions, depend on your settings.

Resources