Acquia Automation: Composer builds

Composer builds allow Remote Admin (RA) clients to efficiently include various scripts and patches, including post-update builds. Both Drupal 8 and Drupal 7 websites may be built using composer.json, but Drupal 7 websites may have additional dependency requirements, as not all modules and distributions include proper Composer packages.

Acquia Automation will update websites that are based on Composer builds whose repositories conform to the proper architecture and include a fully-functioning composer.json file that builds a Drupal website.

Remote Administration will provide updates in the scope of service — third-party vendor libraries and other scripts that may be included using the composer.json file are not in the scope of RA support.

Overview

After Acquia Automation detects that security updates are required on the Production environment, it proceeds in the following fashion:

  1. Acquia Automation scans for the existence of a composer.lock file. If such a file exists, it will be scanned for the presence of Drupal. If Drupal is found, it proceeds as follows. Otherwise, it proceeds with the Drush update process.
  2. Acquia Automation runs composer update drupal/modulename --with-dependencies for all modules that require a security update and which match the RA scope. This updates the modules and their dependencies. All modules are updated unless they are properly pinned to a minor version.
  3. Specified files and paths are preserved.
  4. Included patches are applied.
  5. Included scripts are run if initiated by a post-update command. Development and support of such scripts remains the responsibility of the client.

Requirements

The following items are required for the website's basic architecture:

  • The composer.json file must be located at the repository root.
  • The vendor directory is located in the repository's root. This folder must be under version control, and the proper autoloading must be set up to redirect Drupal to the new vendor location (see Drupal Scaffold).
  • All Drupal code is in the /docroot
  • Composer update replaces the entire module or core directory when performing updates. All non-Drupal files added to any directory must either be excluded using drupal-scaffold or able to be recreated through patches in /patches.

composer.json file

The composer.json file is built from several components, and must meet the following requirements:

  • Be placed at the top level of the repository. This file overrides the drupal/composer.json file.
  • Include all code necessary to run the website.
  • Be able to be installed without package conflicts.

The creation, maintenance, and resolution of any package conflicts in the composer.json file is the responsibility of the client. Acquia can assist in troubleshooting according to normal Support scope.

Composer uses semantic versioning. The caret ( ^ ) indicates all versions greater than what is specified, in the same major release. For example, ^8.2 indicates all Drupal core versions greater than 8.2, but less than 9.0.

The following sections explain the various sections of the composer.json file. These requirements are based on a Drupal 8 build using composer.json. Drupal 7 requirements are specified where they are known.

File requirements

The following sections must be present in the composer.json file in order to build a website.

  • packages.drupal.org

    Including the package itself:

      "repositories": {
        "drupal": {
            "type": "composer",
            "url": "https://packages.drupal.org/8"
        }
      },
  • Composer installers
    Composer Installers is required to install Drupal-specific packages to the correct docroot location:

    "require": {
            "composer/installers": "^1.2.0",
        },

    and the specified Drupal installer paths:

    "extra": {
        "installer-paths": {
          "docroot/core":                     ["type:drupal-core"],
          "docroot/modules/contrib/{$name}":  ["type:drupal-module"],
          "docroot/themes/{$name}":           ["type:drupal-theme"]
        }
      },
  • Drupal scaffold
    The following code ensures that the Drupal docroot structure is preserved during updates and allows the exclusion of files that may be customized (such as robots.txt or .htaccess). Be sure that the drupal-composer/drupal-scaffold line is before the drupal/core line in the file.

    "require": {
            "drupal-composer/drupal-scaffold":            "^2.0.0",
        },
  • Drupal core and modules
    The composer.json file must specify all required Drupal core, distributions and modules, unless a module is included as a dependency of another module or distribution.

      "require": {
        "drupal-composer/drupal-scaffold":            "^2.0.0",
        "drupal/core":                                "^8.2",
        "drupal/acquia_connector":                    "^1.0",
        "drupal/zurb_foundation":                     "^5.0"
      },

    or when a distribution such as Lightning includes core as a dependency:

      "require": {
        "drupal-composer/drupal-scaffold":            "^2.0.0",
        "drupal/lightning":                           "^.2",
          "drupal/memcache":                            "2.0-alpha2",
        "drupal/zurb_foundation":                     "^5"

      },

Recommendations

The following sections are recommended additions to the composer.json file.

  • Security:

        "roave/security-advisories":                  "dev-master",
        “grasmash/drupal-security-warning": "^1.0.0",
  • Minimum Stability:

      "minimum-stability": "dev",
  • Prefer Stable:

      "prefer-stable":     true,
  • Conflict:

    "conflict": {
        "drupal/core": "8.*"
      },

    Or

    "conflict": {
        "drupal/core": "7.*"
      },

Optional items

The following list of items are optional additions to the composer.json file, and may be useful to your installation in some situations.

  • Locking or pinning a module
    RA automation runs composer update drupal/modulename --with-dependencies, not composer require. As a result, if a required item specifies the minor or patch version, RA automation will not update the module. This is equivalent to locking a module.

    This require locks the Token module to a specific version that cannot be updated by RA automation:

      "require": {
        "drupal/token":                                "1.0"
      },

    While the caret is used to specify all versions greater than the specified version, but not exceeding the next major version, locking requires the exact version number to be specified. For this reason, the caret is not used in this example.

    Maintaining the locked status of modules is the responsibility of the client.

  • Patching contributed code
    Patches can be added and will be automatically run by Composer when they are required for a specified module. They may be added locally (ensure the directory exists) or linked remotely. If you have extensive patches, we recommend splitting them into core and module subdirectories. For detailed instructions, see cweagans/composer-patches instructions.
    1. Require cweagans/composer-patches:

        "require": {
          "cweagans/composer-patches":                  "^1.6.0"
        },
    2. Add patches
      Patches can be specified in the extra section of the composer.json. The patch can be local or remote.

          "patches": {
            "drupal/core": {
              "Friendly Ajax": "patches/core_patches/friendly-ajaxExpired-typeError_0.patch"
            },
            "drupal/simplesamlphp_auth": {
              "simplesamlphp dependency should use next significant release operator.": "https://www.drupal.org/files/issues/2760995-2.patch"
            }
          }
    3. Ignore Patches
      If your version of a module should not have a patch applied — for instance, a patch has been applied by a distribution — you can ignore the patch in the extra section:

          "patches-ignore": {
            "drupal/lightning": {
              "drupal/panelizer": {
                "This patch has known conflicts with our Quick Edit integration": "https://www.drupal.org/files/issues/2664682-49.patch"
              }
            }
          }
  • Excluding modified files
    If you have modified included files, or created non-Drupal folders or files in your docroot, you can exclude them using drupal-scaffold settings:

      "drupal-scaffold": {
          "excludes": [
            ".htaccess"
          ]
        },
  • Adding custom library files
    To add a library that is not added by a module-specific composer.json, add the file or repository as a discrete package:
    1. Add as a package in the repositories section of composer.json:

        "repositories": {
          "jquery.cycle": {
            "type": "package",
            "package": {
              "name": "jquery/jquery.cycle",
              "version": "3.0.3",
              "type": "drupal-library",
              "dist": {
                "url": "https://github.com/malsup/cycle/blob/master/jquery.cycle.all.js",
                "type": "file"
              }
            }
          }
        }
    2. Add a libraries path using installer-paths:

        "extra": {
          "installer-paths": {
            "docroot/libraries/{$name}":        ["type:drupal-library"]
          },
        ...
        },
    3. Require the package:

        "require": {
          "jquery/jquery.cycle":                        "3.0.3"
        },

.gitignore file

Composer-based builds typically recommend that directories which will be built by Composer are not committed to the repository. Unless you are using Acquia Pipelines (which is not currently compatible with Remote Administration updates) you cannot build a branch on Acquia Cloud. As a result, you must commit all code required to run a Drupal website, including the following:

  • drupal/core
  • drupal/modules
  • Vendor

Be sure that the top-level .gitignore file is not ignoring these folders.

Sample files

Acquia RA provides an example composer.json template that can be modified on a per-installation basis. You can copy this file, modify it for your application, and then commit it to your code repository above the docroot.

Contact supportStill need assistance? Contact Acquia Support