Updating Drupal 8 using composer, bitbucket pipelines and deployer

Submitted by hernani on Sat, 07/29/2017 - 14:52

Updating Drupal 8 sites via composer can be hard. If you are following good practices you have your website code in a git repository, and you have an environment where you can test your changes before deploying them to production. 

Here are the typical steps you need to do when Drupal core or contrib module is updated:

  • Change composer.json
  • Run composer update
  • Commit the changes to the git repository
  • Deploy to a non-production environment and test to see if everything keeps working
  • Finally deploy to production

If you manage dozens of websites, you can have a hard day when you have a new security release.

Enterprise hosting solutions started to handle this problem by providing better support for deployments based in composer but if you have a smaller hosting solution and access to a build server you can achieve the same with a couple of tools. 

Here comes automation

I am using this strategy for a couple of Drupal websites I manage and host in cheap hosting plans:

There are simple principles and tools which can be adapted to your use case or toolset:

  1. Code is versioned in a git repository (bitbucket). Composer to version drupal core and contrib modules is used and mine is based in drupal composer project.
  2. Two branches are used.
    • Dev branch only contains composer.json and custom modules and themes. It does not have Drupal core or any contrib modules.
    • Dev-build branch contains the full build that is deployed to servers
    • Master branch or tags are used to deploy in production
  3. Bitbucket pipelines is used as the continuous integration solution (CI). It will fetches the code from the repository, build it and push other branches or environments. To use it, you need to host your git repository in bitbucket and maintain a bitbucket-pipelines.yml file in the root of your repository. Here is mine:
    image: hernanibf/hernanibb
    
    pipelines:
        branches:
            dev-build:
                - step:
                    script:
                      - ssh git@server1.pt 'cd /home/git/git_dev/current/deploy;  php ../vendor/bin/dep deploy development -vvv --branch=dev-build; cd  /home/git/git_dev/current/docroot; drush --uri=dev.yourwebsite.com updatedb --y'
            master:
                - step:
                    script:
                      - ssh git@server2.pt 'cd /home/git/git_prod/current/deploy;  php ../vendor/bin/dep deploy production -vvv --branch=master; cd  /home/git/git_prod/current/docroot; ../vendor/drush/drush/drush --uri=yourwebsite.com updatedb --y'
            dev:
                - step:
                    script:
                        - apt-get update && apt-get install --yes zip unzip php-pclzip
                        - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
                        - git config --global user.email "iam@hernani.com"
                        - git config --global user.name "User Bitbucket"
                        - git pull origin dev-build
                        - rm -rf docroot/modules/contrib/*
                        - composer update --verbose --prefer-dist
                        - git remote -v
                        - git add *
                        - git diff --quiet && git diff --staged --quiet || git commit -am 'Built by bitbucket'
                        - git push origin dev:dev-build
  4. All changes are pushed or merged against development branch. Anytime a push against development branch is done, the bitbucket pipelines plan for dev is executed to build the site using composer and push all the changes to dev-build branch. This will trigger the next pipelines job!
  5.  When a push against dev-build is done, another pipelines job is executed to deploy the development branch to a development environment.

    This is done using deployer a PHP tool to deploy code directly from a repository to one or more servers and execute different deployment tasks (run drush cr or drush updatedb for instance)

    For that you just need a recipe describing your repository and servers and locations you need to deploy on. You need access from the location you are executing the deployment job to the git repository and to the servers where the code is going to live. The deployment process will checkout the code and copy it to the right locations in the servers and when ready will swap the symlink serving the docroot. This allows safe deployments and rollbacks in case of failures in any of the servers. Here is my deploy.php
     
    namespace Deployer;
    
    require 'recipe/drupal8.php';
    
    // Configuration
    
    set('repository', 'git@bitbucket.org:myusername/myrepository.git');
    set('allow_anonymous_stats', false);
    
    // Hosts
    host('server1.pt/prod')
      ->stage('production')
      ->set('deploy_path', '/home/git/git_prod');
    
    host('server1.pt/prod')
      ->stage('production')
      ->set('deploy_path', '/home/git/git_prod');
    
    host('server.pt/dev')
      ->stage('development')
      ->set('deploy_path', '/home/git/git_dev');
    
    host('server2.pt/dev')
      ->stage('development')
      ->set('deploy_path', '/home/git/git_dev');
    
    set('shared_dirs', [
      'docroot/sites/{{drupal_site}}/files',
    ]);
    
    //Drupal 8 shared files
    set('shared_files', []);
    //Drupal 8 Writable dirs
    set('writable_dirs', [
      'docroot/sites/{{drupal_site}}/files',
    ]);
    
    // [Optional] if deploy fails automatically unlock.
    after('deploy:failed', 'deploy:unlock');
    
    
  6. When I am happy with my tests on development server, I perform a pull request from dev/build branch to master which will trigger another deployment job that will deploy that branch to production and execute the exact same steps.

The main feature of this development and deployment strategy is that allows for easy changes ( I can eventually just change the composer.json in bitbucket directly) and I have the code deployed to development server first, and production afterwards in a matter of minutes and follow everything from Bitbucket UI:

Bitbucket

Hope this is helpful for you, comments are welcomed !