Setup pull requests with git flow and azure pipelines - azure-devops

I'm trying to setup a library project using DevOps. The branching strategy choosed is git-flow in order to have use git version and follow semver with releases and hotfixes.
So i tried was to protect both develop and release branches by activating pull requests.
Everything works fine unless a release is going to be closed. Here I see two problems:
In git-flow the system try to realign develop from master, but devops doesn't know this is git-flow and just merges release to master.
Develop branch is protected, so if i want to realign manually i should create a new pull request, from master to a feature branch in order to solve conflicts
I'm not sure about the correctnes of the implemented workflow. Is there a better way to accomplish this realignment?
Any suggestions are welcome
Thanks

At present, azure devops is designed like this. Devops can only be one-to-one branch merge at the same time.The release branch cannot be merged into the master branch and into the develop branch at the same time.
When the release is finished, the release branch is merged into master
and into develop too, to make sure that any changes made in the
release branch aren’t accidentally lost by new development.
This feature described in git flow cannot be implemented in azure Devops.
So, your understanding is correct, you can do it manually by your method, although this may be a bit inconvenient.

Related

Development and Production Environments with GitHub flow

At work, we're now using GitHub, and with that GitHub flow. My understanding of GitHub flow is that there is a master branch and feature branches. Unlike git flow, there is no develop branch.
This works quite well on projects that we've done, and simplifies things.
However, for our products, we have a development and production environment. For the production environment, we use the master branch, whereas for the development environment we're not sure how to do it?
The only idea I can think of is:
When a branch is merged with master, redeploy master using GitHub actions.
When another branch is pushed, set up a GitHub action so that any other branch (other than master) is deployed to this environment.
Currently, for projects that require a development environment, we're essentially using git flow (features -> develop -> master).
Do you think my idea is sensible, and if not what would you recommend?
Edit:
Just to clarify, I'm asking the best way to implement development with GitHub Flow and not git flow.
In my experience, GitHub Flow with multiple environments works like this. Merging to master does not automatically deploy to production. Instead, merging to master creates a build artifact that is able to be promoted through environments using ChatOps tooling.
For example, pushing to master creates a build artifact named something like my-service-47cbd6c, which is a combination of the service name and the short commit hash. This is pushed to an artifact repository of some kind. The artifact can then be deployed to various environments using tooling such as ChatOps style slash commands to trigger the deloy. This tooling could also have checks to make sure test environments are not skipped, for example. Finally, the artifact is promoted to production.
So for your use case with GitHub Actions, what I would suggest is this:
Pushing to master creates the build artifact and automatically deploys it to the development environment.
Test in development
Promote the artifact by deploying to production using a slash command. The action slash-command-dispatch would help you with this.
You might also consider the notion of environments (as illustrated here)
Recently (Feb. 2021), you can:
##Limit which branches can deploy to an environment
You can now limit which branches can deploy to an environment using Environment protection rules.
When a job tries to deploy to an environment with Deployment branches configured Actions will check the value of github.ref against the configuration and if it does not match the job will fail and the run will stop.
The Deployment branches rule can be configured to allow:
All branches – Any branch in the repository can deploy
Protected branches – Only branches with protection rules
Selected branches – Branches matching a set of name patterns
That means you can define a job to deploy in dev environment, and that job, as a condition, will only run if triggered from a commit pushed from a given branch (master in your case)
For anyone facing the same question or wanting to simplify their process away from gitflow, I'd recommend taking a look at this article. Whilst it doesn't talk about Github flow explicitly it does effectively provide one solution to the OP.
Purests may consider this to be not strictly Gitflow but to my mind it's a simple tweak that makes the deployment & CI/CD strategy more explicit in git. I prefer to have this approach rather than add some magic to the tooling which can make a process harder for devs to follow and understand.
I think the Gitflow intro is written fairly pragmatically as well:
Different teams may have different deployment strategies. For some, it may be best to deploy to a specially provisioned testing environment. For others, deploying directly to production may be the better choice...
The diagram in the article sums it up well:
So here we have Master == Gitflow main and the useful addition is the temporary release branch from which you can deploy to other environments such as development. What is worth considering is what you choose to call this temporary branch, in the above it's considered a release, in your process it may be a test branch, etc.
You can take or leave the squashing and tagging and the tooling will change between teams. Equally you may or may not care about actual version numbers.
This isn't a million miles away from VonC's answer, the difference is the process is more tightly defined and it's more towards having multiple developers merge into a single branch & apply fixes in order to get a new version ready for production. It may well be that you configure the deployment of this temporary branch via a naming convention as in his answer.
The way I've implemented this flow is using PRs. I did it with Azure DevOps, but I'd say that the same can be achieved with GitHub Actions.
When you have a branch that you intent to test and eventually merge to master and release to production, you create a PR from that branch to master. The PR will trigger a pipeline, which will run your build, static analysis and tests. If that passes, the PR is deployed to a test environment where further automated and manual testing can happen. That PR can be reviewed and approved by other developers and, if you need to, by QA after manual testing. You can configure GitHub PR rules to enforce the approvals. Once approved, you can merge the PR to master.
What happens once in master is independent of the workflow above, but most likely a new pipeline will be triggered, which will build a release candidate and run the whole path to production (with or without manual intervention).
One of the tricks is how the PR pipeline decides which environment to deploy the PR too. I can think of three options:
Create an environment on the fly which will be killed once the PR is merged or closed. This is the most advanced and flexible option. This would require the system to publish the environment location to the PR.
Have a pool of environments and have the automation figure out which are free and automatically choose one. The environments could be stopped, so you find an environment which is stopped, start it up and deploy there. Once the PR is closed/merged, stop the environment again.You can publish the environment location to the PR.
Add a label to the PR indicating the environment (ie. env-1, env-2, etc.). This is the simplest option, but it requires that developers look at the open PRs to see which environments are already in use in other PRs to avoid overwriting other people's code.
With all these options, once the PR is created, you can just push new commits to the branch and the environment will be updated.
You also need to decide what you want to do when a new commit is pushed to master. You most likely want to trigger a new PR build to update the environments with the latest master, but you can do this automatically or manually, depending on how busy your master is.
Nathan, adding a development branch is good idea, you can work on development changes in new branch and test them in dev environment and after getting signoff to move to production environment you can merge your changes in master branch.
Don't forget to perform regression testing on merged master branch to test both old features and new features are working fine before releasing your code for installation in production

Avoid rebuilding artifacts in Jenkins multibranch pipelines

TL;DR
How do I avoid rebuilding artifacts on master when a feature is merged without creating multiple pipelines per project? Where do I access the information about which branch was merged?
More Info
I run Jenkins to build many projects stored in two different VCSs (Gitlab, Bitbucket). Auto-discovery for both VCSs work and create multi-branch pipelines for every project/branch/PR containing a Jenkinsfile (Gitlab Branch Source Plugin, Bitbucket Branch Source Plugin).
Build artifacts get produced and stored on every build (e.g. docker images pushed to registry).
As I follow a feature branch workflow, these features get eventually merged into master, master will then be deployed in irregular intervals.
When doing the merge, there is an artifact already built and stored for this code(see appendix:1). It was built for the feature branch the code originated from (e.g. container mysuperapp:feat-add-better-things-3). I would like to take this artifact and promote it as the new master artifact (e.g. mysuperapp:master), avoiding a rebuild (and unit + integration testing everything).
But, merging a feature branch just kicks off a new build pipeline on branch master without any information about the merged branch (see appendix:2). This is correct behavior concerning master (new commit(s) where pushed) but prevents me from reacting to the merged branch (e.g. the aforementioned promoting or even just deleting unused artifacts). Is there any way to get the information, which branch was merged?
I am aware, that I can create a new pipeline listening for PR webhooks from my VCSs, running a pipeline to do the promotion and ignore builds on master completely. But this moves visibility of this process to a different pipeline and requires additional pipelines for projects, e.g. reducing the advantage of auto-discovery to 50% (have to create these merge pipelines for each project).
How can I keep the advantages of auto-discovery and visibility of executed steps while also executing something on a merge?
Ideas: Tag artifacts differently, but how (needs to be able to clean up correctly)? Parameterize pipelines and setup a single merge pipeline which re-triggers the pipeline 'push on master' with parameters of the merged branch. But can this be done without having to setup the webhooks for every project? Ask the VCSs via REST about which branch belonged to a commit?
Greets and thanks for the help you all! This may be a complicated one, but it would be so cool to get this to work. It's the last barrier for me to enable continuos delivery for a lot of projects!
Appendix:
1: I am also aware, that to have consistent builds, I have to enforce --ff-only merges. This question is not about the pitfalls of git but rather about the way to go with Jenkins.
2: Git provides me with the parent commits, I can easily find out, which commit was merged. But, especially using "Delete branch after merge", leaves me without the branch ref in git. Tagging my docker images with commits instead of branches leaves me with backtracking the last commit on each build to delete the old, obsolete build.

Building a previous release using the original Build Pipeline at the time of release

We are following gitflow model in our project using Azure DevOps Services. I have a classic editor based pipeline which builds the Dev and Release/R1.0 branch.
I am going to setup a classic editor based pipeline which will build my Release R.10 from the master branch after merging Release/R1.0 branch at the end of the release. Let us say this classic editor based build pipeline is MyProduct-R1.0
After the release, I will be tagging the master branch and deleting the Release/R1.0 branch as per GitFlow model. However, I will be retaining the build pipeline MyProduct-R1.0
My question is this: Suppose after the Release R1.0 once master branch has moved ahead and I want to do a build of master branch at R1.0 tag, how do I do using the MyProduct-R1.0 pipeline which was used to originally build the R1.0 release?
I know this is possibly a confusing question, but I have tried my best to give it a shot.
Thanks,
Update 2: I think my question is more about the branch specification for my MyProduct-R1.0 release pipeline. I can't give master since master will evolve after the Release R1.0. I can't give Release/R1.0 since this branch will be deleted after the Release as per gitflow model. So what branch specifications should I provide for my pipeline?
Use YAML builds. There's no mechanism for this with JSON ("classic editor") builds, since JSON builds are versioned separately from source code.
Like Daniel said YAML is the best path. Handles this gracefully as the Build definition lives with the branch.
In the past for GUI builds, when I dealt with build definition drift, instead of creating new build definitions, I would use conditional steps tied to the branch that was being built, but it can be painful to go back and update\maintain.
I think here is what will achieve what I am after. Once I do my release and tag it as R1.0, then I can always use my pipeline at a later date to build the same source code in the master branch for R1.0 using either it's tag or the commit it.
Note that this shows Dev is my default branch for this pipeline as it is not yet the Release pipeline which I depict below. I am yet to create it.
Am I missing something?

How to implement Git tag and merge on release?

The final stage of our release pipeline is a manual stage used to confirm the deployed release got its final acceptance. Among the tasks we would like to run in this stage:
Tag the develop branch with the release label. Say "1.2.3".
Merge the develop branch into the master branch.
(We're using Azure Git repositories)
Although it looks like the right moment to make these changes in Git, I'm not quite certain this is the intended usage of Azure release pipelines. I confess being a bit new to Azure pipelines and there seem to be no evident pipeline task for doing such changes.
However, I believe this kind of post-release SCM changes is quite common.
My question is therefore: Where and how is the proper way to apply those SCM changes in Azure Devops ?
EDIT: I could make it work to use a command line task to run git commands. Config was passed by means of a variable group.
You can just do the regular git commands in a Command Line script (first , clone the repo (or add it as an artifact), then tag/merge).
Or install the Tag Git on Release & Git Merge extensions and use them.

Branching strategy - for multiple release with gihub

I am working on the project where currently we have following three fixed branches
Develop - The code is deployed to development environment. It's a base branch for anyone who want to add new feature.
Release - Deployed in QA environment, And QA can start testing on.
Master - Deployed to Production environment and available to clients.
And we have two more dynamic branches, feature and hotfix.
Anyone wants to start new development or bugfix, forks new feature from develop branch, then then creates a pull request.
once development is done it's testing in Development environment from develop branch it then creates a merge request for release branch
QA deploys the release branch on Test environment and start testing, once testing is done. it's merged to master and then deployed to production.
This all works well for most of the part. However, it has following problem
Not every feature in QA (release branch) is tested and ready for deployment (merge to master) at the end of the release. And so we are not sure how to create a pull request as it will select all the commits.
I am thinking Github releases might be a solution for this. I can create a new release with which ever feature is ready for deployment and then merge these releases with master branch.
However, what I am not sure is when to deploy to production, from releases or from master ?
You should be following the standard Git Flow:
Instead of merging any feature to the release branch (from develop) after testing, what you'll want to do is make use of a 'release cut'. This is a dedicated point in time at which you decide you want to make a release. Features that are planned to be in this release are evaluated and tested, and the release is confirmed.
You'll want to tag your releases, and optionally include any assets that are associated with that release for future reference. If it's a mobile app, this is a great place to include your .apk or .ipa. After the release cut has been made and tagged, you'll then want to release the release branch to production. Once that has been deployed out to production, you'll then want to merge release into both master and develop.
Under this approach, every feature branch will end up in develop, then release (with a corresponding tag), then master. If a feature is still in progress when the release cut is made, it simply doesn't make the cut! It will get added to the next release. This will give it adequate time for testing before it comes anywhere near release, let alone master. In this regard, master should be a mere representation of your last-known 'good state' -- a point at which you were happy to release to the public.
Also, note that hotfixes and bugfixes are two different things, and neither should branch from develop. Bugfixes should be made to the release branch itself, and hotfixes should be created from master, and merged back into both master and develop.