Tips for Implementing a Software Release Process
Implement a release process for managing and controlling software application releases
Software Development process is not complete and mature without a well-defined release process for the software applications. Every software application needs to be delivered or deployed at some point in time and for agile projects, this is happening more often. Therefore, there is a need to maintain software quality across the application releases to avoid deploying untested or malicious code to production environments.
Defining a release process for software applications helps in ensuring that software releases maintain a constant release quality. In addition, software changes and new features are traceable or can be correlated to specific releases easily. As a result, changelogs and release notes are easier for a generation.
I this post, I will discuss some of the most important topics and areas regarding defining a release process for a software application and will provide some tips for the implementation of these topics.
Assuming that the software application is using
git as the version control system of your application, It is important to decide and define the used workflow in the project. There are a couple of git workflows that are already known and widely used by projects and teams, these workflows are
- Centralized Workflow: This workflow is suitable for projects and teams who are migrating from SVN such as Subversion. This workflow is utilizing a central repository with a single branch
master, Engineers clone the repository, checkout
masterbranch locally, develop new features and then merge the local
masterbranch into the origin
- Git Feature Branch Workflow: This workflow is almost the same as the centralized workflow except it is designed to shift the development process from the master branch to the feature branches. Here we still have one centralized repository and a
masterbranch. However, the development of new features should be done on dedicated branches. Therefore the development process will be done using the following steps:
→ First, the Engineers need to clone the repository.
→ Then create new branches from the
master branch (These branches are called feature branches).
→ After a successful implementations engineers can issues pull request to discuss the change and merge it back to
The main advantages of this workflow over the centralized workflow are: First it is possible now to keep master clean and free of bugs and second it is also possible that more than one engineer to work on the same feature branch without disturbing the main codebase (This can be done simply by pushing the feature branch to the origin and all contributors will be able to checkout and use that branch).
- Gitflow Workflow: This workflow is designed to be used with projects using a scheduled release process. The workflow is defining the actions that need to be done during the release processes as well as how to perform these actions and how to contribute to the source code. Below is a brief overview of key items of the workflow
- Two branches are used for the development: the master branch is the branch that is used to store the official release history and used for the deployment and only should include stable code versions. The other branch is the “develop” branch which is the main repository branch where all new features are merged.
- Multiple types of branches are used during the software development cycle such as
Featurebranches are created from
developand merged into
developbranch when they are completed.
Releasebranches are created from
developand merged into
developbranches when they are successfully tested and approved.
Hotfixbranches are created from
masterbranch in case of a bug in master and merged into
developbranches when they are done.
- Forking Workflow: This workflow is different from the previous workflows fundamentally because it utilizes more than one repository. Each contributor will have to fork the main repository often called
upstreamand have his own copy of the repository. As a result, each contributor will have two copies of the repository one local copy one remote copy. This will allow the contributors to work independently and there is no need for pushing to a centralized repository unless there is a need for integrating the changes into the
upstream. Also, there is no need for granting permissions for every contributor to the
upstreamrepository. This workflow is used mostly in public open-source projects.
Now we have an idea about the git workflows The question is, which one is the best and which one should we use?
The answer to the above question is highly dependent on what is the project needs and what we are trying to achieve, plus the above workflows are not the only ones and we can define our workflow based on our needs. Below I will present a custom workflow that can be also used for managing a release process.
Hybrid workflow: I called this workflow
hybrid because it is based on both the
Gitflow and the
Forking workflows. Below are the main key points that describe the workflow and the actions needed during the release cycle.
- Each new project repository should have two branches, the
masterbranch representing the latest version of the software and the “develop” branch which is the main branch of the repository and where all new changes or features need to be integrated.
- Engineers who would like to contribute to the project need to fork the project repository to their namespace. The forked repository will be called the
originwhile the project main repository will be called
upstreamremote will be used by all contributors and source code integration will be done on it.
- The upstream repository should only have the following branches at any given time:
- Contributors will start by cloning the project repository form their fork and adding the
upstreamremote to the project.
featurebranches should user upstream develop branch as a base branch. It is important to pull all changes from upstream using the command
git pull upstream developand then creating the feature branch form the
git checkout -b feature_x upstream/develop.
- After completing the work on a feature branch pull requests need to be created to merge the changes for the contributor repository to the
- Release branches need to be created form the
developbranch and pushed to the
- In case a bug found in the release branch a bugfix branch is created for the release branch and once the fix is complete the bugfix branch is merged back into the release branch.
- Once the release is done, The release branch needs to be merged with
masterbranch and the
masterbranch, then tag the
masterbranch with the release tag and merge the
- In case a bug is found in the productions environment a hotfix branch needs to be created form the
masterbranch and once the fix is implemented and tested the hotfix branch needs to be merged into
masterbranch, tag the
masterbranch and merge it into
Managing software releases and implementing a solid release process is definitely relies on managing and collecting the changes on the source code. This is important because it will help in producing and compiling release notes during the release process and it will help in tracing the roots of bugs and changes to the affected releases. For instance, in case of finding a bug on the master branch, after identifying the root cause of the bug the change log process can help in identifying which of the software release are affected by the bug and which ones need to have hotfixes or security updates.
Implementing a change log process can be very simple, however, it can be also very complicated. As a simple and straight forward solution that does not require a lot of resources, the changelog can be implemented by a single text file added to the project repository. This file should include a list of all the changes introduced to the source code. We can improve and enhance the quality of the changelog file by following the below points
- Ensure the change log process by requiring the update of the changelog file with each of the pull requests that introduce a change in the source code.
- Define a schema or a template for adding new changes to the changelog file. For instance, each change item should have the following required attributes:
→ A category which can be one of
Refactoring (you can define these categories based on your needs).
→ The severity of the change indicates if the change is introducing breaking changes for the future release or not. do we change the application API with this change?
→ A clear description of the change.
→ Any special instructions (if there is any) that need to be applied for upgrading the software application.
You can argue that we can use the
git history for this purpose instead of introducing a new file for the changes on the source code 🤔, I can agree with this statement in case that we keep the git history as clean as possible, by having a clear description of the changes in the
git commits and allowing only
one commit per
pull requestor better per
feature. However, I think that is difficult to achieve especially if a large team or multiple teams are contributing to the source code. Moreover, merge and revert commits can introduce some noise on the
On the other hand, The changelog process can be implemented by other tools such as issue tracking tools like Redmine or JIRA. Issue tracking tools provide sophisticated mechanisms or methods to be able to track issues status and progress. Below I describe an Idea for implementing a change log process with such tools:
- Restrict all the changes on source code to have an
issue ticket. NO code or any change is merged without a ticket.
- Tickets are well defined and have a clear description and acceptance criteria.
- Once a ticket is resolved or closed, it should be reviewed by the release manager and assigned a
fixVersionvalue, this is an attribute that represents the potential release number that this change will go with.
- Reports can be created using the issue tracking tools to list all the changes introduced to a given release version based on the value of the
A release cycle is a cycle of actions or events that take place during the process of creating new releases of a software application. These actions can be done by different departments, engineers or even CI/CD pipelines. Below I listed the stages/actions that need to be covered during the release process by any release cycle.
This is the stage where the change in the source code will take place, all the new features, improvements and refactoring tickets should be implemented during this stage. This stage is mostly done by the engineers who contribute to the source code and can be facilities by product owners and product managers to prioritize the tickets that need to be implemented in each of the releases. The engineers should follow the project workflow for integrating new changes into the project source code and the
Changelog policy can be controlled either by the release manager or the engineers.
- Code freeze
The release cycle process is highly affected by the code freeze policy defined in the project. The term code freeze means that the integration of any new features or changes into the release source code is forbidden after the freeze date. 😕 so are we going to stop the development? and how long this can last?.
The development of new features should not be affected by the code freeze (at least if it is implemented properly ). The code freeze is more about isolating a version of the source code that could represent a candidate version of the source code for the next release. This goal can be achieved simply by creating a new branch (
release branch ) from
upstream develop branch, Only bug fixes should be allowed to be merged with this branch.
The period needed for the code freeze on the release branch depends on the reediness of the release branch itself. if the release branch has too many bugs and needs a lot of fixes this could take a long time or even the release could be canceled. One the other hand, if the release branch if free of bugs this can take much less time.
Despite the fact the release redlines period cant be estimated or figured out before starting the release process, it is possible to control or minimize the risk of having too long code freeze periods by ensuring the quality of the code. For example, implementing CI/CD pipelines to validate the code quality, execute the unit tests, check for Security Vulnerabilities in each of the pull requests can help in sustaining a healthy “develop” branch that is free of syntax errors at least 😆. In addition, Automating the integrations and performance testing will definitely help in reducing the time needed for testing the release branch (especially in case we need to perform these tests more than once due to bug fixes).
- Stage deployment:
Once the code freeze takes place and the release branch is created and pushed to the upstream repository, The stage or pre-production deployment could take place. These environments should look like the production environment as much as possible to able to simulate running the source code in production environments.
- Release Testing
Once the release is delayed to the stage/pre-production environments the verifications of the release branches can take place. In this stage, several actions can be done depending on the resources available for the project. below is a list of some actions that could be implemented here.
- Running the integration tests suites against the deployed applications. All features so far should be covered by the unit tests, however, if the software application is is a microservice or an application that can be integrated with other applications/microservice, There is a need to test the integration with these applications. For instance, If the application is supposed to expose an API for mobile applications or consume the APIs from another application, then there is a need to test the uses cases for such cases on the stage environment.
- Running E2E test integrations, This is related to the previous point and can be considered as an integration test, but I want to make it explicitly clear that there is a need to perform integrations tests uses cases without the usage mock services.
- Manual testing of the deployed applications: QA engineers can perform manual testing to verify the quality of the release candidate version and make sure that there are no bugs in the release. This is a very important step especially if the integration tests and unit tests suites are not covering every single use case or feature supported by the application.
- Running Performance Testing: It is also important to make sure that the release is maintaining a certain performance quality. For example, for applications that expose
httpAPIs, it is good to measure how many concurrent API requests that the application can handle and to maintain this across all releases. Performance testing could results in improvements not only on the source code but also on the hosted environments too.
- Running Penetration testing: It also important to test the software form a security point of view and try to find any security holes or vulnerabilities in the software application.
The next stage after completing the release testing and approving the release candidate is to start preparing the release package. Steps that should be done during this stage need to done by multiple engineers (for small projects this could be done a single engineer):
- Compile the release notes based on the changelog file or the tickets contributed to the release. The Release notes should be written in a way that is easy to understand and does not require deep technical skills. This is one of the changes between the release notes and changelog. The changelog audience is technical people who need to know what is the exact change on the release and in most cases is only used internally by the contributors to the source code. While the release notes are meant to be read by people who would like to use the software, therefore it should be clear and focus on the added value of the release.
- Follow the
Project workflowto prepare the project repository for packaging the software. This step can be done by one of the contributors or by the release manager and it may involve merging the
matserbranch with the release version, and maybe creating a release on the git repository.
- Execute all CI/CD pipelines that are needed for generating the packages needed for the release deployment. This could involve compiling source code, liking packages, and building docker images needed for the release.
- Deployment or Delivery
The last step in the release cycle is the deployment/delivery of the release packages. This is dependent on the project itself, in cases that the production environment is managed by the development team the deployment of the release most probably will be included in the release cycle. On the other hand, if the production environment is managed by other entities such as external customers, the deployment will not be part of the release cycle. As a result, the delivery or distribution of the release package to the customer could be considered the last step of the release cycle.
Implementing a release process is a necessity for most of the software development projects. The implemented process should define the release cycle and the actions taken during each of the stages of the release cycle as well as the adopted project workflow. In the next post, I will discuss and show what parts of the release cycle can be automated and to which degree.