📜 ⬆️ ⬇️

GitFlow and Semantic Versioning for every day

image

How much time I use GitFlow and Semantic Versioning , everything does not leave me feeling that something is missing in them. Both concepts are good, but since they offer solutions for problems from different areas, their sharing looks more complicated than they should be.

Perhaps the reason is that I chose not the most optimal way, and this could be a good topic for a future post. In this same I want to describe a simple approach to managing releases of applications and libraries.

Problem


How to make sure that the release build does not get into production without proper integration testing? How to make sure that the NuGet package will not be published until it passes the test with a static analyzer?
')
Most of the tools that could solve these problems already exist, and we often use them “in manual mode”. In fact, you only need to automate all this slightly, but this requires entering appropriate agreements and patterns.

Instruments


We describe the current state of affairs.

Environments


As long as we do not have the capacity or infrastructure to test production, the classic approach would be to use different environments for different phases of the release life, such as integration or acceptance tests. It would be good to always be sure that a specific assembly of the application will be able to get only to the environment corresponding to it. To do this, we need the ability to uniquely identify each version.

Semantic versioning


Before we go into the details of what exactly we should assign versions, we need to think about how to generally version the software. This topic is not new, and fortunately there is a Semantic Versioning, although in versions of which you still have to figure it out .

A nice bonus for .NET developers is the almost complete support of this approach by NuGet and most public packages .

Gitflow


For most of the projects I've worked with, GitFlow seems like a fairly natural choice to me. If it turns out to be too complicated due to the frequency or number of changes, then you can always “roll back” to GitHub Flow , where each change is the so-called “hot fix”.

I want to note that for this model Git is not required at all. What actually write ALM Rangers. Although, with Git, this model works easier than with Subversion.

I will not consider in detail the various strategies for working with branches that are already well documented .

What is worth forgetting


In the good old days, when most of the tools mentioned above were missing or not so widely used, it was common practice to gradually deploy one version through all environments. One such approach was to commit binary files to a special repository, and to further advance through branches corresponding to different environments. Sometimes this led to meaningless merdzham and even conflicts in the configuration files. Often it was “flavored” with custom deployment scripts for Robocopy.

A large number of manual operations are error prone. As a rule, if there is a possibility to make a mistake, then most likely it will be made. Therefore, please forget this approach, like everything you read in the previous paragraph.

Next approach


Let's take a look at how we can apply the above concepts together with the appropriate tools.

Artifacts


For convenient identification, we version the artifacts produced by the build server: builds and libraries. The basic requirement is the ability to associate an artifact with the source of the change (the commit hash in Git) and the process that generated the artifact (build ID). Most CI tools have internal assembly counters, which makes this information available.

To work with reusable components (libraries), the standard in the .NET world is the package manager (NuGet). Using the deployment manager, such as Octopus Deploy , allows you to apply the same concept to all the artifacts supplied. But how exactly to collect and link this meta-information and artifact?

Branches and releases


Instead of using branches corresponding to environments, let's create artifacts that already contain information about the environment they should be assigned to. In other words, we will associate a specific artifact with a specific environment. Knowing what each of the environments is used for, and having this meta-information, we can automatically make decisions about the next stage of deployment.

First we need to determine how stable the artifact is, built from a specific branch:
BranchRelease typeVersion format
featurealpha# major. # minor. # revision-a # build # feature
developbeta# major. # minor. # revision-b # build
releaserelease candidate# major. # minor. # revision-r # build
hotfixrelease candidate# major. # minor. # revision-r # build
masterstable# major. # minor. # revision

Using the above format, we can describe assembly metadata , for example in general for all assemblies (assebmly) file in a project.
[assembly: AssemblyVersion("#major.#minor")] [assembly: AssemblyFileVersion("#major.#minor.#revision.#build")] [assembly: AssemblyInformationalVersion("#major.#minor.#revision[-prerelease]")] 

For AssmeblyInformationalVersion we use the format defined in the previous table.
Thus, the versions are numbered according to Semanic Versioning for runtime as well as for identifying the CI build and for the version of the result package.

Using the example of GitFlow-based steps, the versions of the NuGet packages produced by the CI system after a commit to the appropriate branch will look like this:
TaskBranchCI build numberNuGet Package Version
Implement feature # 1feature-1one1.2.0-a1feature1
Implement feature # 2feature-221.2.0-a2feature2
Implement feature # 1feature-131.2.0-a3feature1
Complete feature # 1developfour1.2.0-b4
Complete feature # 2developfive1.2.0-b5
Stabilize releaserelease-1.2.061.2.0-r6
Release to productionmaster71.2.0
Fix production issuehotfix-1.2.1eight1.2.1-r8
Release to productionmaster91.2.1

This pattern well reflects the natural order of increasing release readiness when sorting packages by version.
When creating a release or hotfix, I prefer to increase the version number manually in the general file with metadata and commit it to the repository. Thus, the version number will be relevant for local copies of the project.

Deployments


The important point is to protect against accidental deployment of the wrong environment. As a first line of defense can be a CI server, a crashing build that fails unit tests. In addition, when using GitHub, you can pay attention to the so-called protected branches .

In Octopus Deploy, there is the concept of lifecycles , which allows us to gradually release through various environments. However, with the approach considered in this article, we get different artifacts for each of the deployment stages. This means that we need to monitor that each artifact is deposited only on the environment allowed to it.
Release typeAllowed environments
alphaD
betaT, d
release candidateA, T, D
stableP, A, T, D

If our Deployment manager does not support this setup of different life cycles depending on the version of the build at the native level, then as a rule you can implement it yourself in the form of a simple script. By coding information about the build type into the build version, we get a simple and reliable tool for “safe” and automated creation of releases and their deployment. Such automation is possible, as with the use of Automatic Release Creation in Octopus Deploy, as well as with the so-called Release Train, which is launched according to a schedule.

Alternatives


The same numbers in the release and in the version of the package looks suspicious. In fact, there is no separation of the concepts of release and artifact. This is especially noticeable in the case of NuGet packages for libraries, where it would be nice to have a separate version numbering scheme. Such a scheme can be based on tags in VCS (do you mark releases with tags?).

Relatively recently, I came across GitVersion , which supports these concepts natively, and at the same time provides the possibility of flexible configuration. Obviously, it makes sense to pay attention to him.

Conclusion


In this article, we looked at a simple approach to managing release builds of applications and individual components (libraries). I hope these ideas will be useful to you in one form or another.

[Translator's note] This is the ambiguous approach to managing releases. Colleagues, I suggest you tell us how the releases and versioning are arranged for you?

Links


Source: https://habr.com/ru/post/267889/


All Articles