Documentation PortalBack to Self Assist PortalBack
Documentation Portal
Contents

CloudOne Usage: Release Flow and Git Flow - V 3.6

Introduction

The main flow of an application through CloudOne is flexible but generally modelled after a code branching methodology called Release Flow, which is a simplified version of a methodology called Git Flow. The CI/CD pipelines in CloudOne can implement both types of software life-cycle flows. Many of the design concepts within CloudOne are consistent with the Release Flow software life-cycle flow, by default.

The purpose of this document is to describe the two flows and how, using new v3.6 features, to modify the normal flow of software through the CloudOne environment to produce a Git Flow model or an alternative flow. These options include the use of a new type of hostspace called the devint space and new features for the conditional use of hostspaces depending on the Git branches triggering the pipeline.

Overview of Release Flow

Release Flow is a methodolofy for managing source code repositories through the software life-cycle, assuming a mostly linear progression of software development combined with defect fixes and other unplanned events that impact a software product's release timeline. The model is very common in many development environments, however was more formally defined and described by Microsoft in an article found at: https://docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/release-flow.

The Microsoft article goes beyond describing a Git branching strategy and also describes their overall release management process and how their Release Flow model fits into it. The article also mentions some unique capabilities within Azure DevOps that help to support the overall release model.

The follow diagram illustrates the Release Flow: cloudone-alt-git-flow

and the flow is best understood with the following annotations accompanying the diagram:

Feature Development

  • Feature branch (feature/*) checked out from master branch
  • Development and fixes to defects from unit testing applied to the feature/* branch
  • Following development, feature/* branch merged back into master branch

Releases

  • Release branch (release/*) checked out from master branch
  • Fixes to defects from UAT applied to the release/* branch
  • Deployment to production from release/* branch
  • Following deployment, release/* branch merged back into master branch

Hot Fixes (emergency defect fixes of production code)

  • Hot fix (hotfix) branch checked out from master branch
  • Following deployment back to production, hotfix branch merged back into master branch

Additional Git Flow References

For more information and context regarding Release Flow, consider reviewing the following:

Overview of Git Flow

Git Flow refers to an alternative methodology for managing source code repositories through the software life-cycle, taking into account what is often a more non-linear nature of software development combined, again, with defect fixes and other unplanned events that impact a software product's release timeline. Sometimes Git Flow also refers to a tool set associated with the Git command-line, called git-flow that supports this methodology; however the methodology can exist and be maintained independent of these tools and this document focuses specifically on the methodology.

What the Git Flow methodology describes is a way to manage the various branches of a Git repository through the life of a software application's or component's releases, including unplanned bug fixes. The follow diagram illustrates this flow:

cloudone-alt-git-flow

and this flow is best understood with the following annotations accompanying the diagram:

Feature Development

  • Development (develop) branch checked out from master branch
  • Feature branch (feature/*) checked out from develop branch
  • Development and fixes to defects from unit testing applied to the feature/* branch
  • Following development, feature/* branch merged back into develop branch

Releases

  • Release branch (release/*) checked out from develop branch
  • Fixes to defects from UAT applied to the release/* branch
  • Deployment to production from release/* branch
  • Following deployment, Release/* branch merged back into master branch AND develop branch

Hot Fixes (emergency defect fixes of production code)

  • Hot fix (hotfix) branch checked out from master branch
  • Following deployment back to production, hotfix branch merged back into master branch AND develop branch

Additional Git Flow References

For more information and context regarding Git Flow, there are several articles available online, including the following ones:

Comparison Between Release Flow and Git Flow

Differences between Release Flow and Git Flow

The main difference between the 2 flows and methodologies is really the develop branch and the role of the master branch in the life-cycle of the software.

In the Release Flow methodology, the master branch represents intent; the branch contains code that will eventually be released to production. Production is, itself, represented by the last release branch used to deploy.

In the Git Flow methodology, the master branch represents current state of production while intent is represented by the develop branch (and the next release branch, once a release is planned).

Common Benefits of Both Flow Models

Some of the benefits shared by the Flow models include:

  • Provides for isolation between new development and completed work, making parallel development safer
  • Enables collaberation on the same features since the developers working on any particular feature branch are isolated from the activities of other developers
  • Creates a natural staging area for all the features rolled up into a release
  • Accomodates an alternate life-cycle of code, such as hot fixes, isolated from new development that might otherwise creep into production prematurely
  • Supports other agile development artifacts and ceremonies by organizing changes and change logs/commits by features for easier code review
  • Accomodates different kinds of release management policies and flows

CloudOne Support for Flow Methodology

The flow of an application through the CloudOne CI/CD pipeline is, out of the box, most similar to that of Release Flow. The pipeline is usually triggered by a merge request to a feature branch that will initiate the Continuous Integration stage of pipeline processing. Following this stage and the progression of deployments in the subsequent Continuous Delivery stage, a merge to the master branch is completed.

The process described above completes the git branch life-cycle in a manner consistent with Release Flow and is also quite similar to that of Git Flow. This flow works well for small and most medium size releases. It is also consistent with the short-term ephemeral nature of the Workspace used for Unit tests before proceding with deployments to various hostspaces.

However, when following a methodology like Git Flow perhaps for larger size releases or in the case of other alternative life-cycle options, additional hostspace environments may be needed and may be associated with specific Git branches, driving a need to support an alternate flow through the deployment sequence in CloudOne to match an alternate life-cycle for software updates reflected in the Git branching.

Support for Alternate Flows

For situations when alternate flows are needed in the CI/CD pipeline flow, a new feature was added to version 3.6 of the CloudOne CI/CD Pipeline:

  • Conditional deployment hostspaces

Conditional deployment hostspaces

One of the implications of supporting alternate flows of software through a release cycle is that not every stage (or hostspace) defined in the CI/CD pipeline is appropriate to deploy into for every run of the pipeline. The choice of which of more than one flow to follow can depend on differentiating between a feature and a release, using the terminology of both the Release Flow and Git Flow models.

For example, it may be that for a feature, characterized as a specific and granular set of changes to an application, the desired flow would be to deploy to an environment for testing for an indefinite period, while a release is expected to continue its flow into more advanced testing environments and on to production.

So while the default flow in CloudOne might look like the following:

cloudone-alt-git-flow

an alternative flow, distinguishing between the small discreet changes of features before being rolled up into a release, might look like the following:

cloudone-alt-git-flow

In order to accomodate such alternate flows, version 3.6 of the CI/CD pipeline introduces conditionals to the definition of a hostspace in the azure-pipelines.yml file. By defining a condition: YAML value, the Continuous Delivery stage of the pipeline can conduct tests to determine if a given hostspace should be included in the flow. The kinds of conditions that can be evaluated are related to the Git branches and merges used to trigger the CI/CD pipeline. In this manner, the CI/CD pipeline can distinguish between different kinds of code promotions (release, feature or hotfix) and advance the software through the appropriate hostspaces in accordance with those defined conditions.

In order to conditionally include a given hostspace in the CI/CD flow, add a YAML condition: expression for that particular hostspace (at the same level where the spacename*: value, for example, is defined). An example setting for the condition: YAML value might be:

hostspaces:
...
  devint:
  - spacename: devexp-devint-1
    condition: and(succeeded(),startsWith(variables['Build.SourceBranch'],'refs/heads/feature'))
    ...

Such a conditional expression would evaluate a built-in Azure DevOps variable (Build.SourceBranch) that points to the Git branch against which the Continuous Integration build is running and would check if it starts with a pattern indicating the branch is a feature branch (i.e. following a name pattern of feature/* where the * is the feature name of the branch under the feature group of branches). A similar conditional expression would be added to every hostspace (and the workspace, as well) where the intent is only to deploy for certain Git branches.

It is important to note that the Build.SourceBranch variable only points to the branch of interest when a pipeline is run manually. When a pipeline is automatically triggered to run because of a pending pull request, that variable points to a temporary branch following a different naming convention and the conditional logic described above will not work. So a more complete conditional expression to use would follow this example:

hostspaces:
...
  devint:
  - spacename: devexp-devint-1
    condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/feature'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/feature')))
    ...

This more complex conditional expression still evaluates the Build.SourceBranch variable, however in the case of an automatically triggered pipeline run, it would evaluate a second variable as well. That variable is System.PullRequest.TargetBranch which is populated with the name of the branch that the pull request will ultimately update once the pipeline completes successfully. Depending on whether the pipeline is automatically triggered or manually run, only one or the other of these variables will be populated with the target branch to be updated, requiring an or boolean function in the condition to take both scenarios into account.

Depending on where the conditional expressions are placed, the resulting conditional pipeline flows could look as follows. The first image shown is a pipeline running for a feature branch and the second image shows the same pipeline with exactly the same version of the azure-pipelines.yml file, when run from a release branch.

CI/CD Pipeline Flow for Feature Branch: cloudone-alt-git-flow

CI/CD Pipeline Flow for Release Branch: cloudone-alt-git-flow

Note the different branches listed under the Branch / tag column at the bottom of each screenshot along with the differences in the corresponding pipeline Stages processed for each respective branch's CI/CD flow.

The more complete example of the YAML code in the azure-pipelines.yml file that produced the flow illustrated in the examples above would look like the following (subset of the YAML code specifically describing the deployment spaces):

  parameters:
    caasImageVersion: ${{ parameters.caasImageVersion }}
    workspace:
      helm:
        overrideFiles: |
          devexp-caas/values.workspace.yaml
      condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/release'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/release')))
    hostspaces:
      devint:
      - spacename: devexp-stg-2
        ref: st2
        condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/feature'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/feature')))
      stage:
      - spacename: devexp-stg-1
        ref: st1
        helm:
          overrideFiles: |
            devexp-caas/values.hostspace.yaml
        condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/release'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/release')))
      prod:
      - spacename: devexp-prd-1
        condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/release'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/release')))
        helm:
          overrideFiles: |
            devexp-caas/values.hostspace.yaml
        ref: prd1
        dependsOn:
        - st1
      - spacename: devexp-prd-2
        condition: and(succeeded(),or(startsWith(variables['Build.SourceBranch'],'refs/heads/release'),startsWith(variables['System.PullRequest.TargetBranch'],'refs/heads/release')))
        ref: prd2
        dependsOn:
        - st2
        helm:
          overrideFiles: |
            devexp-caas/values.hostspace.yaml