DRUPAL8 DEVELOPMENT STANDARDS

Coding Standard and Best Practices

Abstract This document covers best practices to be followed by all developers who will be working on development and implementation of a Drupal8 CMS on Acquia platform for UNICEF.

ICTD-Solution Center and Services Table of Contents

1 Executive summary ...... 3 2 List of standardized tools which should be used while working on Drupal8 Project...... 4 3 Creating a new Drupal8 codebase ...... 4 4 8 implementation structure (where do I find what) ...... 5 4.1 Directory Structure ...... 5 4.2 Install Profile ...... 5 4.3 Modules ...... 5 4.4 Themes ...... 6 4.5 Test directory structure ...... 6 5 Coding standards ...... 7 6 Theme standards ...... 7 7 Automated Testing ...... 7 7.1 Coding standard Test ...... 7 7.2 Functional Test ...... 7 8 Git Usage and workflow ...... 8 8.1 Pull Requests, commits and Code Review Guidelines ...... 8 8.2 Naming Conventions when using Git ...... 9 8.3 Developer Workflow ...... 9 8.4 Deployment Via BLT ...... 10 9 Best practices for project/website development ...... 10 9.1 Composer Dependencies ...... 10 9.2 Configuration Management ...... 11 9.3 Custom Code ...... 11 9.4 Updates...... 11 9.5 Variables naming ...... 11 9.6 Theme best practices ...... 12 9.7 Definition of DONE during development process ...... 12 10 Best practices for PR code review ...... 12 10.1 Preparation steps ...... 12 10.2 General checks ...... 13 10.3 JavaScript-related checks ...... 13 10.4 Twig-related checks ...... 13 10.5 CSS and Sass-related checks ...... 13 10.6 PHP-related checks ...... 14 10.7 YAML-related checks ...... 14 10.8 Automated Checks ...... 14 10.9 Definition of DONE during code review process ...... 15 11 Resources & additional information ...... 15

1 Executive summary

The purpose of this document is to provide guidelines, recommendations and the minimum mandatory requirements, which should apply to any Drupal 8 CMS based implementation using the Acquia platform and authored by or under the responsibility of any UNICEF office.

UNICEF development standards are built to ensure a coherent and cohesive Drupal 8 implementation strategy across the organization as well as better quality, robustness and maintainability during development, launch and post-launch.

UNICEF development standards require the use of Acquia BLT framework with Drupal native configuration management. Using Acquia BLT enforces the development to use a set of tools, such as Composer and as the dependency management tools, and a Continuous Integration tool (such as Travis). In addition, UNICEF highly recommends the use of a Drupal VM for easier integration with BLT.

UNICEF requires to use configuration management approach (file-based) instead of regular SQL database storage, in order to benefit from a versioning system for configuration in any Drupal 8 implementation.

In order to enable easier compliance of these standards, UNICEF will provide a Composer file, which will include the list of approved Drupal modules. This Composer file will be required to be used to create the project. In addition, UNICEF will provide a private Github repository under UNICEF Github organization account where all development should happen.

Regular audits might be performed by UNICEF technical team to ensure compliance of UNICEF development standards.

Additional requirements, guidelines and best practices are found in the document below. 2 List of standardized tools which should be used while working on Drupal8 Project

The below list includes a (non-exhaustive) list of required and recommended tools to be used in any Drupal 8 implementation.

Name of tool Description Ticketing/Project UNICEF highly recommends the use of a project tracking tool which support tracking agile/scrum based projects (e.g. VSTS, Github Issues, JIRA) tool Github UNICEF requires the use of Github as the control versioning tool. Acquia BLT UNICEF requires the use of Acquia BLT for deployment, build and test. Continuous UNICEF highly recommends the use of Travis CI for seamless integration with Integration Acquia BLT. Bootstrap UNICEF requires the use of Bootstrap as the base theme Acquia Lightning UNICEF requires the use of Acquia lightning distribution profile. distribution

3 Creating a new Drupal8 codebase

UNICEF requires to use composer to manage dependencies with the codebase. For creating a new Drupal8 codebase, UNICEF will provide composer files. Any deviation from the included core and contributed modules and versions will have to communicated/coordinated with UNICEF development team for approval before implementation.

Please note that UNICEF composer includes Acquia BLT framework to manage and deploy code and database, as well as Acquia lightning distribution and additional contributed modules those are approved by UNICEF.

UNICEF standards highly recommends the use of Drupal VM, as it provides a self contained environment for local development. More information is found at https://www.drupalvm.com/

UNICEF standards requires the use of Drupal native configuration management approach (file- based), as it provides a versioning system for configuration instead of regular SQL database storage. More information on configuration management is found at https://www.drupal.org/docs/8/configuration-management 4 Drupal 8 implementation structure (where do I find what)

This section describes the required implementation architecture structure that should be followed:

4.1 Directory Structure

Top-Level directories

/blt /config /docroot /composer.json /travis.yml

Second-level directories

/docroot/modules/ /docroot/profiles/ /docroot/sites/ /docroot/themes/

4.2 Install Profile

Install profile in Drupal 8 has all the functionality of modules, including access to hooks and plugins and, critically, the ability to provide configuration for the site in the form of .yml files.

The profile name should consist of lowercase letters and underscore only.

Creation of the profile should be based on the lightning profile. For more details about how to create sub-profile, refer to Acquia's documentation - https://docs.acquia.com/lightning/subprofile

Should the codebase make use of different profiles, the below structure should be followed.

/docroot /profiles /custom /profilename /config/ /modules/ /README.md /profilename.info.yml /profilename.install /profilename.profile

4.3 Modules

The code base should include the following structure for contributed and custom modules:

/docroot /modules /contrib /custom/ /example/ /example.module /example.info.yml /example.libraries.yml /example.install

NOTE: The list of approved modules is included in the UNICEF composer file. Please note that any additional contributed modules required for the project should be communicated/coordinated with UNICEF technical team for approval before implementation.

4.4 Themes

The code base should include the following structure for sub-themes:

/docroot /themes /contrib /custom /sitetheme /assets /images /templates /sitetheme.info.yml /sitetheme.libraries.yml /sitetheme.info.yml /sitetheme.breakpoints.yml

4.5 Test directory structure

The code base should include the following structure for testing files, which will be created as part of Acquia BLT configuration:

/Tests /behat - contains all Behat tests /features /bootstrap /Example.feature /behat.yml - contains behat configuration common to all behat profiles. /integration.yml - contains behat configuration /phpunit - contains all PHP Unit tests 5 Coding standards

The Drupal community has outlined some pretty comprehensive coding standards for code written and contributed to the Drupal community. The same standards should apply to any UNICEF Drupal 8 project. All the code should comply to the coding standards defined at https://www.drupal.org/docs/develop/standards

6 Theme standards

Any custom theme should be created from base theme bootstrap, as a sub-theme. New theme should follow SASS theming standard defined at https://drupal- bootstrap.org/api/bootstrap/docs%21Sub-Theming.md/group/sub_theming/8

NOTE: The theme should be used strictly as a display layer and should not contain large amounts of business logic or other JS/code.

7 Automated Testing

Drupal 8 development should include automated test coverage as below:

7.1 Coding standard Test

BLT includes automated testing for coding standards through linting/sniffing by default. More information is found in section 10.8 Automated checks.

7.2 Functional Test

Behat Tests: Any development should include Behat test for all business logic and user interfaces that are accessible via the browser. Functionality should be expressed as a behavioral test for automated testing.

By default, the two primary areas of testing should be on the content model/content structure implementation and user roles & permissions.

At a minimum each Pull Request submitted by a developer should include either a complete behavioral test of the 'sunny skies' scenario of the story being built, or an update to an existing scenario if this is a bug fix.

Behat resources can be found in a variety of places, here are a few extra reading links: http://behat.org/en/latest/user_guide/context.html http://docs.behat.org/en/v2.5/guides/1.gherkin.html https://media.readthedocs.org/pdf/behat-drupal-extension/latest/behat-drupal-extension.pdf

Examples of Behat tests can also be found at: /vendor/drupal- extension/src/Drupal/DrupalExtension/Context/DrupalContext. /docroot/profiles/contrib/lightning/tests/features/*

PHPUnit Test: PHPUnit integration/unit test should be used for functionalities that are not reachable by the browser. Examples: inside Cron logic, server-to-server communication of any kind, API integrations, etc. The Drupal community maintains an excellent documentation.

8 Git Usage and workflow

All development should be done in a version control system, such as Git. Github software should be used. Please contact UNICEF technical team to get a UNICEF private repository for your project.

When working with Github and Acquia, the following rules and workflow should be followed:

• The main git repository should contain at least a develop, a master and a hotfix branch • All developers will work on their forked version of the repository • Development can happen in parallel on different branches. Once finished should be merged to Develop branch • Developers will create pull requests against their main repository • Once a pull request happens, a code review should be done by another developer, before being merged to the main repository. • Stable code will be released via Release branch (created from develop branch), it will be tagged accordingly for production release and moved to master branch. • Hotfixes will be managed by a hotfix branch and will be deployed to Prod environment via another tag. • Hotfix branch will later merged to develop • Developers will be allowed to push directly to the Acquia dev environment.

Regular audits might be performed by UNICEF technical team to ensure compliance of UNICEF development standards.

On those special cases when the project/website will live under the same codebase managed by UNICEF development team, all deployments to staging and production environment will be handled by UNICEF, once a code review is approved by UNICEF team.

8.1 Pull Requests, commits and Code Review Guidelines

Pull requests have a number of aspects that should be followed:

• The title of the pull request should include the ticket number and description. E.g. "VSTS- 1234: Fix template style on hero image”. Pull requests should only contain the work relevant to the story being resolved. Do not combine issues, or attach 'rider along code' that is unrelated. Discussion during the review process should be kept civil. It is important to remember that the code being reviewed is not art, and issues raised are only helpful to the cause. Commit messages should identify the ticketing system issue number they are related to. Note that this will not always line up with the number identified in the branch. for example, if VSTS-1234 has a subtask, that issue might be referenced in the commit. EG: "feat(new_module): 1235 - Added micro version handling." Commits should be isolated to working groups of changes only. Do not commit non- functional code, or split functionality between commits if they are dependent on each other. Code reviews should follow best practices for theme review, as found in https://www.drupal.org/docs/develop/standards/css/what-to-look-for-when-reviewing-

8.2 Naming Conventions when using Git

The below naming conventions is recommended when committing and pushing code.

• commit message – Format is “task_type (very short task desc): task_id – description of commit” Task types are: o feat (new feature) ▪ eg- feat(search): 1564 - updated search block markup o fix (bug fix) ▪ eg: fix(country): 1564 - error for country module dependency. o docs (changes to documentation) ▪ style (formatting, missing semi colons, etc; no code change) o refactor (refactoring production code) ▪ eg: refactor(migration): 1564 - removes duplicated migration file o test (adding missing tests, refactoring tests; no production code change) o chore (updating grunt tasks etc; no production code change) Branch Naming - o ▪ feature - New feature. ▪ release - New release. ▪ hotfix - Quick fixes to the codebase. ▪ junk - Experiments (will never be merged). o . Always use dashes to separate words, and keep it short. Examples: ▪ feature-renderer-cookies ▪ release-3.0 8.3 Developer Workflow

This section describes the workflow that developers should follow when committing their work to the main repository.

Create a new/update an existing feature: o Developer should create your own fork (forked repository) from main project repository (upstream repository) o On your local system you execute git clone on e.g. https://github.com//main-repository-name to get a local copy of the repo $ git clone https://github.com//main-repository-name o Add remote to local clone of forked repository (link local clone to upstream repo) $ git remote add upstream https://github.com/unicef/main-repository-name o You create a new feature branch in your local clone repo called feature-name $ git checkout -b feature-name o Work is done to complete the new feature and git commit is executed to save the changes $ git commit -a -m "Add first draft of migration code” o Take latest code changes from original upstream repo (Run this command when there is new updates on original repository) ** $ git pull upstream develop $ git merge develop o You then push the new feature branch to your remote forked repository $ git push origin feature-name o Using github you open up a pull request for the new branch “feature-name” against the original repo at github.com/unicef/main-repository-name “develop” (merge should be performed using –no-ff flag or Git merge from interface, do not use either squash or rebase merge)

o Once merged delete your branch - git branch - feature-name

8.4 Deployment Via BLT

As a vendor, you will need to deploy to Acquia cloud environment. The deployment should happen automatically after Pull Request gets merged to the main repository if you are using Travis CI. The configuration for the Travis CI should be similar as follows:

Configure the deployment at blt/project.local.yml: git: default_branch: migration-build remotes: '[email protected]:unicef.git'

More information about deployment workflow is found in: https://blt.readthedocs.io/en/latest/readme/deploy/

More information about continuous integration is found in: https://blt.readthedocs.io/en/latest/readme/ci/

9 Best practices for project/website development

The following are a list of best practices that should be followed by any Drupal CMS project. Many of these are driven by the project's use of Acquia BLT.

9.1 Composer Dependencies

Contributed modules, and libraries must not be included in our code base. All external code (code managed in public repositories) should be added as composer dependencies, and given proper upgrade paths. Any modules, or components that require patches should have those patches added to the master composer.json file, with accurate descriptions associated with each patch.

9.2 Configuration Management

All Drupal configuration should be exported to code in the form of config management using config split and ignore that can be deployed to the site. Configuration should be exported to the config/ path outside of the document root.

For multisite implementations on single codebases, config-split over feature based implementation should be adopted.

9.3 Custom Code

Custom code should always 'live' with the configuration it supports. Sometimes this means it exists in and is maintained in a feature module - Considering these modules are auto-generated, this may sound strange but the source files where this code is housed is always preserved during exports, making these modules the ideal location for the glue-code that supports them.

Sometimes custom modules are not directly tied to a feature. In these cases the module should be moved to the /docroot/modules/custom folder, which will be maintained and tracked via Git (unlike its 'contrib' counterpart).

9.4 Updates

Access to upstream environments should strictly be controlled, and a "zero touch" process is in place. This means that no manual changes can take place on the servers, every update must be deployed automatically. This comes in the form of 'hook_update_n()' functions. These functions are required when any of the following conditions are needed:

Fields are renamed Fields are deleted Fields are changed from one data type to another Fields are moved from one entity type to another Data is manipulated Content must be created

All of the reasons above must also be taken into account in either the module's config/install folder, or in the hook_install() function, depending on the use case. For example: A renamed field must have the config/install folder adjusted to take into account the new field name, and a hook_update_n() needs to be created to transition the data to the new field, and remove the old field. Creating a mandatory node however, it does not need the config/install folder adjusted, but does need to be handled in both hook_install() and a hook_update_n() function.

9.5 Variables naming When creating a new component/template starting from Front-end side, these instructions should be followed to map the variables name to be used in templates.

• Prefix should start with ‘field_’ plus field name. e.g: field_[name] -> field_author Body and Title are Drupal default fields, and the should be kept as it is. If necessary, the same structure as above should be followed. e.g.: field_body or field_title

This way rework at variable’s renaming will be avoided since it will match both sides.

If development starts with Back-end side first, then this variable naming convention should also be followed and Front-end will replicate the same variable names in templates.

9.6 Theme best practices

UNICEF recommends to use drupal 8 theme standards documentation found in https://www.drupal.org/docs/develop/standards/css/css-architecture-for-drupal-8.

9.7 Definition of DONE during development process

The below information is used by UNICEF development team to ensure the quality of the process during development process. UNICEF recommends to follow these rules:

The work of the developer is considered done when:

✓ Functionality passes the acceptance criteria ✓ Manual test is provided, modified if needed and passing ✓ Automated test is provided if needed and passing ✓ Code complies to Drupal coding standards, and the guidelines & best practices mentioned in this document ✓ A pull request is created, assigned to a reviewer and How-To-Test are provided ✓ CI build is passing ✓ If issue type is bug, a short description of the solution is provided ✓ The issue has been set to a reviewer with the correct status 10 Best practices for PR code review

This section covers pull request code review best practices. UNICEF recommends following them when reviewing other developers’ work.

10.1 Preparation steps

1. Checkout the PR code:

`git fetch pull//head:` (e.g `git fetch unicef pull/265/head:Release20171201`) `git checkout Release20171201`

2. Open the source code of the project in an IDE This is helpful to quickly look up relevant source code parts, or rely on the built-in inspections of the 1 IDE.

10.2 General checks

Check the naming of functions, PHP classes, CSS classes, files, constants, SASS mixins, etc. The names should be clear and concise. Duplicated or very similar, code parts are problematic and should be removed in every file type. Code comments should be checked, that it's not copy and pasted with irrelevant pieces, and that it is meaningful and provides value for the reader of the source code. This applies to every file type. Check whitespaces in every file type.2 Commented out code parts should be removed in almost every case, Git history is there to restore any previous state if needed. Check for obviously not used variables, rules, files, classes. Check if Travis passed for the last commit.

10.3 JavaScript-related checks

Check the use of the Javascript API: Behaviors, settings, context.3 Check Javascript code format.4 • Excessive amount of custom, project-specific JavaScript code is a “code smell,” for a typical Drupal project. Most functionality should be solved in PHP or using a JavaScript-based library. Check that errors of any kind are handled properly (e.g., unsuccessful HTTP requests)

10.4 Twig-related checks

BLT does validation automatically. Check for indentation and spacing issues. Check for absolute, hard-coded URLs that might cause issues if the base URL changes. Check for HTTP-only included resources (will result in mixed content warning).

10.5 CSS and Sass-related checks

1 For PhpStorm, see https://confluence.jetbrains.com/display/PhpStorm/Drupal+Development+using+PhpStorm ; For .io, see https://atom.io/packages/linter-drupalcs 2 https://www.drupal.org/docs/develop/standards/coding-standards#indenting 3 see https://www.drupal.org/docs/8/api/javascript-api/javascript-api-overview. 4 https://www.drupal.org/docs/develop/standards/javascript/javascript-coding-standards - use eslint to check automatically (https://www.drupal.org/node/1955232). Check code format.5 If in doubt that something is valid SASS, compile it.6 Check for HTTP-only included resources (will result in mixed content warning).

10.6 PHP-related checks

Use local static code analysis, like Drupal coding standard check, to spot obvious problems, see below, report all issues. Check for security issues, SQL injections and XSS. SQL injection can come from un-sanitized user input, directly appended to SQL query. XSS typically come from unsanitized user input sent to the output without filtering.7 Check for hard-coded paths, hard-coded URLs. Check for HTTP-only included resources (will result in mixed content warning). Check for proper usage of the Drupal API. If there is an API function or class for the purpose, custom code should not be written, rather the code should rely on the existing solution. This is the hardest part of the code review, as it requires an extensive knowledge of Drupal. Errors of any kind should be handled and logged with Logger properly. Check for validation of data forms. Validation should happen when accepting data from the user, typically handled by the Drupal API. Do performance-related checks, to determine if something seems to be a resource-heavy operation. If so, question it; check if it's cache-able

10.7 YAML-related checks

Follow https://www.drupal.org/docs/develop/coding-standards/configuration-file-coding-standards

10.8 Automated Checks

Setting up PhpCS8

The ruleset can be found at the installed project too: vendor/drupal/coder/coder_sniffer

If for any reason, it's needed globally (for other projects, contributed modules and so on): git clone --branch 8.x-2.x https://git.drupal.org/project/coder.git cd coder composer install

5 https://www.drupal.org/docs/develop/standards/css/css-formatting-guidelines 6 http://beautifytools.com/scss-compiler.php 7 Refer to https://www.drupal.org/docs/8/security/writing-secure-code-for-drupal-8 for details 8See https://github.com/squizlabs/PHP_CodeSniffer and http://drupal.org/project/coder Bash aliases:

These aliases should be appended to .bash_profile (MacOSX) or to .bash_rc (Linux): alias codingstd='/vendor/bin/phpcs -- standard=/vendor/drupal/coder/coder_sniffer/CodeSniffer/Standards/Drupal/ru leset.xml --extensions=php,module,inc,install,test,profile,theme' alias drupalpr='/vendor/bin/phpcs --standard=/vendor/drupal/coder/coder_sniffer//CodeSniffer/Standards/DrupalPr actice/ruleset.xml --extensions=php,module,inc,install,test,profile,theme'

Setting up ESLint

Drupal 8 provides ESLint configuration out-of-the-box. To perform the initial setup: cd docroot/core npm install

Then to inspect an individual file:

/docroot/core/node_modules/eslint/bin/eslint.js [target_custom_js]

10.9 Definition of DONE during code review process

The below information is used by UNICEF development team to ensure the quality of the process during the code review process. UNICEF recommends to follow these rules:

The work of the code reviewer is considered done when:

✓ The code looks good ✓ The How-To-Test steps can be executed ✓ The manual test is executed successfully ✓ The pull request is merged into the correct branch ✓ The issue has been completed 11 Resources & additional information

Below is a set of URLs to documentation pertaining to various topics covered above and or general reference resources.

• Acquia's Documentation: https://docs.acquia.com/documentation • Acquia's BLT: https://blt.readthedocs.io/en/8.x/ • Travis CI Documentation: https://docs.travis-ci.com • Composer: https://getcomposer.org