Jenkins devops - Revert features automatically

Posted by: Emlyn Kinzett May 3rd, 2016 Comments

The Features module in Drupal provides a user interface and an API to bundle together different site components and exportables into a single feature module. This module contains information so configuration can be checked, updated or reverted programmatically.

After requests from several different clients, the ability to revert Drupal Features automatically during deployment with Jenkins was incorporated into our CI scripts. This was implemented in two steps; the first, we simply created the ability to turn on or off automatic feature reverting through a flag in the config.ini file (which is an essential file in our deployment process).

By adding two lines to the config.ini file, such as below, a developer can enable this feature:

fra: True

Upon deployment, the script would search for the [Features] section and if it finds it, stores the boolean value of the fra option in a variable, as seen below:

fra = False
  if config.has_section("Features"):
    fra = config.getboolean("Features", "fra")

While this worked, it effectively would revert features on all sites. Sometimes, that wasn’t the desired behaviour. For example, the developers may not want features to revert automatically on the production site, or on a particular development branch. To accommodate this, a comma separated list of branches on which to revert features can be added to a branches option in the config.ini file, resulting in the following:

fra: True

The deployment script was edited to check if a branches option exists in the config.ini file, but only if the fra boolean option is set to True. The script looks something like this:

# Set the default fra value
  fra = False
  # If config.ini has a [Features] section, proceed on
  if config.has_section("Features"):
    # Get the value of fra in config.ini
    fra = config.getboolean("Features", "fra")
    # If set to true, proceed on
    if fra == True:
      # Create an empty list
      branches = []
      # If a 'branches' option exists in the [Features] section in config.ini, proceed
      if config.has_option("Features", "branches"):
        # Get the 'branches' option from under the [Features] section
        revert_features = config.get("Features", "branches")
        # Split the 'branches' option using a comma as a delimeter
        revert_features = revert_features.split(',')
        # For each value, strip it and add it to the branches list, which will be searched later
        for each_branch in revert_features:
          each_branch = each_branch.strip()
      # If a 'branches' option does not exist in the [Features] section, add master and stage
      # to the branches list. This is prevent any current jobs using the previous version of
      # this function to break
        branches = ['master', 'stage']

So, using the example [Features] section above, the script would add master, stage, uat and sandbox into a list which is checked later on in the deployment process; if the branch value being passed to the Jenkins script is in that list, features will be reverted automatically on that site.

if fra == True:
  if branch in branches:
    drush_fra(repo, branch, build)

If the fra option is set to True, but a branches option is not included, the script will revert features on the master and stage sites by default.

Image of Emlyn KinzettEmlyn Kinzett