├── .ansible-lint ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── .yamllint ├── LICENSE ├── README.md ├── defaults └── main.yml ├── handlers └── main.yml ├── meta └── main.yml ├── molecule └── default │ ├── converge.yml │ ├── deploy.yml │ ├── molecule.yml │ ├── requirements.yml │ ├── test-setup.yml │ └── test-vars.yml └── tasks ├── backwards-compatibility.yml ├── build-composer-project.yml ├── build-composer.yml ├── build-makefile.yml ├── deploy.yml ├── install-site.yml ├── main.yml └── update.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | skip_list: 2 | - 'yaml' 3 | - 'no-handler' 4 | - 'role-name' 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | --- 3 | github: geerlingguy 4 | patreon: geerlingguy 5 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 'on': 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | schedule: 9 | - cron: "30 5 * * 1" 10 | 11 | defaults: 12 | run: 13 | working-directory: 'geerlingguy.drupal' 14 | 15 | jobs: 16 | 17 | lint: 18 | name: Lint 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Check out the codebase. 22 | uses: actions/checkout@v4 23 | with: 24 | path: 'geerlingguy.drupal' 25 | 26 | - name: Set up Python 3. 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: '3.x' 30 | 31 | - name: Install test dependencies. 32 | run: pip3 install yamllint 33 | 34 | - name: Lint code. 35 | run: | 36 | yamllint . 37 | 38 | molecule: 39 | name: Molecule 40 | runs-on: ubuntu-latest 41 | strategy: 42 | matrix: 43 | include: 44 | # See: https://github.com/geerlingguy/docker-rockylinux9-ansible/issues/6 45 | # - distro: rockylinux9 46 | # playbook: converge.yml 47 | - distro: ubuntu2404 48 | playbook: converge.yml 49 | - distro: debian12 50 | playbook: converge.yml 51 | - distro: debian12 52 | playbook: deploy.yml 53 | 54 | steps: 55 | - name: Check out the codebase. 56 | uses: actions/checkout@v4 57 | with: 58 | path: 'geerlingguy.drupal' 59 | 60 | - name: Set up Python 3. 61 | uses: actions/setup-python@v5 62 | with: 63 | python-version: '3.x' 64 | 65 | - name: Install test dependencies. 66 | run: pip3 install ansible molecule molecule-plugins[docker] docker 67 | 68 | - name: Run Molecule tests. 69 | run: molecule test 70 | env: 71 | PY_COLORS: '1' 72 | ANSIBLE_FORCE_COLOR: '1' 73 | MOLECULE_DISTRO: ${{ matrix.distro }} 74 | MOLECULE_PLAYBOOK: ${{ matrix.playbook }} 75 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This workflow requires a GALAXY_API_KEY secret present in the GitHub 3 | # repository or organization. 4 | # 5 | # See: https://github.com/marketplace/actions/publish-ansible-role-to-galaxy 6 | # See: https://github.com/ansible/galaxy/issues/46 7 | 8 | name: Release 9 | 'on': 10 | push: 11 | tags: 12 | - '*' 13 | 14 | defaults: 15 | run: 16 | working-directory: 'geerlingguy.drupal' 17 | 18 | jobs: 19 | 20 | release: 21 | name: Release 22 | runs-on: ubuntu-latest 23 | steps: 24 | - name: Check out the codebase. 25 | uses: actions/checkout@v4 26 | with: 27 | path: 'geerlingguy.drupal' 28 | 29 | - name: Set up Python 3. 30 | uses: actions/setup-python@v5 31 | with: 32 | python-version: '3.x' 33 | 34 | - name: Install Ansible. 35 | run: pip3 install ansible-core 36 | 37 | - name: Trigger a new import on Galaxy. 38 | run: >- 39 | ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }} 40 | $(echo ${{ github.repository }} | cut -d/ -f1) $(echo ${{ github.repository }} | cut -d/ -f2) 41 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Close inactive issues 3 | 'on': 4 | schedule: 5 | - cron: "55 3 * * 1" # semi-random time 6 | 7 | jobs: 8 | close-issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | steps: 14 | - uses: actions/stale@v8 15 | with: 16 | days-before-stale: 120 17 | days-before-close: 60 18 | exempt-issue-labels: bug,pinned,security,planned 19 | exempt-pr-labels: bug,pinned,security,planned 20 | stale-issue-label: "stale" 21 | stale-pr-label: "stale" 22 | stale-issue-message: | 23 | This issue has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 24 | 25 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 26 | close-issue-message: | 27 | This issue has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 28 | stale-pr-message: | 29 | This pr has been marked 'stale' due to lack of recent activity. If there is no further activity, the issue will be closed in another 30 days. Thank you for your contribution! 30 | 31 | Please read [this blog post](https://www.jeffgeerling.com/blog/2020/enabling-stale-issue-bot-on-my-github-repositories) to see the reasons why I mark issues as stale. 32 | close-pr-message: | 33 | This pr has been closed due to inactivity. If you feel this is in error, please reopen the issue or file a new issue with the relevant details. 34 | repo-token: ${{ secrets.GITHUB_TOKEN }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.retry 2 | */__pycache__ 3 | *.pyc 4 | .cache 5 | 6 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: 6 | max: 160 7 | level: warning 8 | 9 | ignore: | 10 | .github/workflows/stale.yml 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Jeff Geerling 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ansible Role: Drupal 2 | 3 | [![CI](https://github.com/geerlingguy/ansible-role-drupal/actions/workflows/ci.yml/badge.svg)](https://github.com/geerlingguy/ansible-role-drupal/actions/workflows/ci.yml) 4 | 5 | Builds and installs [Drupal](https://drupal.org/), an open source content management platform. 6 | 7 | ## Requirements 8 | 9 | Drupal is a PHP-based application that is meant to run behind a typical LAMP/LEMP/LEPP/etc. stack, so you'll need at least the following: 10 | 11 | - Apache or Nginx (Recommended: `geerlingguy.apache` or `geerlingguy.nginx`) 12 | - MySQL or similar Database server (Recommended: `geerlingguy.mysql` or `geerlingguy.postgresql`) 13 | - PHP (Recommended: `geerlingguy.php` along with other PHP-related roles like `php-mysql`). 14 | 15 | Drush is not an absolute requirement, but it's handy to have, and also required if you use this role to Install a Drupal site (`drupal_install_site: true`). You can use `geerlingguy.drush` to install Drush. 16 | 17 | Git is not an absolute requirement, but is required if you're deploying from a Git repository (e.g. `drupal_deploy: true`). You can use `geerlingguy.git` to install Git. 18 | 19 | ## Role Variables 20 | 21 | Available variables are listed below, along with default values (see `defaults/main.yml`): 22 | 23 | ### Deploy an existing project with Git 24 | 25 | drupal_deploy: false 26 | drupal_deploy_repo: "" 27 | drupal_deploy_version: master 28 | drupal_deploy_update: true 29 | drupal_deploy_dir: "/var/www/drupal" 30 | drupal_deploy_accept_hostkey: false 31 | 32 | Set `drupal_deploy` to `true` and `drupal_build_composer*` to `false` if you would like to deploy Drupal to your server from an existing Git repository. The other options all apply to the Git checkout operation: 33 | 34 | - `repo`: Git repository address 35 | - `version`: can be a branch, tag, or commit hash 36 | - `update`: whether the repository should be updated to the latest commit, if `version` is a branch 37 | - `dir`: The directory into which the repository will be checked out 38 | - `accept_hostkey`: Whether to automatically accept the Git server's hostkey on the first connection. 39 | 40 | You can also control whether a `composer install` is run after the git clone is finished using the following variable: 41 | 42 | drupal_deploy_composer_install: true 43 | 44 | ### Build a project from a Drush Make file 45 | 46 | drupal_build_makefile: false 47 | drush_makefile_path: "/path/to/drupal.make.yml" 48 | drush_make_options: "--no-gitinfofile" 49 | 50 | Set this to `true` and `drupal_build_composer*` to `false` if you would like to build a Drupal make file with Drush. 51 | 52 | ### Build a project from a Composer file 53 | 54 | drupal_build_composer: false 55 | drupal_composer_path: "/path/to/drupal.composer.json" 56 | drupal_composer_install_dir: "/var/www/drupal" 57 | drupal_composer_no_dev: true 58 | drupal_composer_dependencies: 59 | - "drush/drush:^10.1" 60 | 61 | Set `drupal_build_makefile` to `false` and this to `true` if you are using a Composer-based site deployment strategy. The other options should be relatively straightforward. 62 | 63 | drupal_composer_bin_dir: "vendor/bin" 64 | 65 | If you set the `bin-dir` in your project's `composer.json` file to a value other than `vendor/bin`, override this variable with the same directory path. 66 | 67 | ### Create a new project using `composer create-project` (Composer) 68 | 69 | drupal_build_composer_project: true 70 | drupal_composer_project_package: "drupal/recommended-project:^9@dev" 71 | drupal_composer_project_options: "--prefer-dist --stability dev --no-interaction" 72 | 73 | Set this to `true` and `drupal_build_makefile`, `drupal_build_composer` to `false` if you are using Composer's `create-project` as a site deployment strategy. 74 | 75 | ### Required Drupal site settings 76 | 77 | drupal_core_path: "{{ drupal_deploy_dir }}/web" 78 | drupal_core_owner: "{{ ansible_ssh_user | default(ansible_env.SUDO_USER, true) | default(ansible_env.USER, true) | default(ansible_user_id) }}" 79 | drupal_core_owner_become: false 80 | 81 | The path to Drupal's root, along with the ownership properties. If you are not running Ansible as the user that should have ownership over the core path, specify the desired system user in `drupal_core_owner` and set `drupal_core_owner_become: true`. 82 | 83 | drupal_db_user: drupal 84 | drupal_db_password: drupal 85 | drupal_db_name: drupal 86 | drupal_db_backend: mysql 87 | drupal_db_host: "127.0.0.1" 88 | 89 | Required Drupal settings. When used in a production or shared environment, you should update at least the `drupal_db_password` and use a secure password. 90 | 91 | ### Drupal site installation options 92 | 93 | drupal_install_site: true 94 | 95 | Set this to `false` if you don't need to install Drupal (using the `drupal_*` settings below), but instead copy down a database (e.g. using `drush sql-sync`). 96 | 97 | drupal_domain: "drupaltest.test" 98 | drupal_site_name: "Drupal" 99 | drupal_install_profile: standard 100 | drupal_site_install_extra_args: [] 101 | drupal_enable_modules: [] 102 | drupal_account_name: admin 103 | drupal_account_pass: admin 104 | 105 | Settings for installing a Drupal site if `drupal_install_site` is `true`. If you need to pass additional arguments to the `drush site-install` command, you can pass them in as a list to the `drupal_site_install_extra_args` variable. 106 | 107 | ## Dependencies 108 | 109 | N/A 110 | 111 | ## Example Playbook 112 | 113 | See the example playbooks used for Travis CI tests (`tests/test.yml` and `tests/test-deploy.yml`) for simple examples. See also: [Drupal VM](https://www.drupalvm.com), which uses this role to set up Drupal. 114 | 115 | - hosts: webserver 116 | vars_files: 117 | - vars/main.yml 118 | roles: 119 | - geerlingguy.apache 120 | - geerlingguy.mysql 121 | - geerlingguy.php-versions 122 | - geerlingguy.php 123 | - geerlingguy.php-mysql 124 | - geerlingguy.composer 125 | - geerlingguy.drush 126 | - geerlingguy.drupal 127 | 128 | *Inside `vars/main.yml`*: 129 | 130 | drupal_install_site: true 131 | drupal_build_composer_project: true 132 | drupal_composer_install_dir: "/var/www/drupal" 133 | drupal_core_path: "{{ drupal_composer_install_dir }}/web" 134 | drupal_domain: "example.com" 135 | 136 | ## License 137 | 138 | MIT / BSD 139 | 140 | ## Author Information 141 | 142 | This role was created in 2014 by [Jeff Geerling](https://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/). 143 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Set this to 'true' and specify a Git repository if you want to deploy Drupal 3 | # to your server from an existing repository. 4 | drupal_deploy: false 5 | drupal_deploy_repo: "" 6 | drupal_deploy_version: master 7 | drupal_deploy_update: true 8 | drupal_deploy_dir: "/var/www/drupal" 9 | drupal_deploy_accept_hostkey: false 10 | drupal_deploy_composer_install: true 11 | 12 | # Set this to 'true' and 'drupal_build_composer*' to 'false' if you would like 13 | # to build a Drupal make file with Drush. 14 | drupal_build_makefile: false 15 | drush_makefile_path: "/path/to/drupal.make.yml" 16 | drush_make_options: "--no-gitinfofile" 17 | 18 | # You can configure the `bin-dir` in your project's composer.json `config` key. 19 | drupal_composer_bin_dir: "vendor/bin" 20 | 21 | # Set 'drupal_build_makefile' to 'false' and this to 'true' if you are using a 22 | # Composer-based site deployment strategy. 23 | drupal_build_composer: false 24 | drupal_composer_path: "/path/to/drupal.composer.json" 25 | drupal_composer_install_dir: "{{ drupal_deploy_dir }}" 26 | drupal_composer_no_dev: true 27 | drupal_composer_dependencies: 28 | - "drush/drush:^10.1" 29 | 30 | # Set this to 'true' and 'drupal_build_makefile', 'drupal_build_composer' to 31 | # 'false' if you are using Composer's create-project as a site deployment 32 | # strategy. 33 | drupal_build_composer_project: true 34 | drupal_composer_project_package: "drupal/recommended-project:^9@dev" 35 | drupal_composer_project_options: "--prefer-dist --stability dev --no-interaction" 36 | 37 | # Required Drupal settings. 38 | drupal_core_path: "{{ drupal_deploy_dir }}/web" 39 | drupal_core_owner: "{{ ansible_ssh_user | default(ansible_env.SUDO_USER, true) | default(ansible_env.USER, true) | default(ansible_user_id) }}" 40 | drupal_core_owner_become: false 41 | drupal_db_user: drupal 42 | drupal_db_password: drupal 43 | drupal_db_name: drupal 44 | drupal_db_backend: mysql 45 | drupal_db_host: "127.0.0.1" 46 | 47 | # Set this to 'false' if you don't need to install Drupal (using the drupal_* 48 | # settings below), but instead copy down a database (e.g. using drush sql-sync). 49 | drupal_install_site: true 50 | 51 | # Settings for installing a Drupal site if 'drupal_install_site:' is 'true'. 52 | drupal_domain: "drupaltest.test" 53 | drupal_site_name: "Drupal" 54 | drupal_install_profile: standard 55 | drupal_site_install_extra_args: [] 56 | drupal_enable_modules: [] 57 | drupal_account_name: admin 58 | drupal_account_pass: admin 59 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: clear opcache 3 | shell: > 4 | cd {{ drupal_core_path }} && 5 | {{ drush_path }} eval "if (function_exists('apc_clear_cache')) { apc_clear_cache(); }; if (function_exists('opcache_reset')) { opcache_reset(); }" 6 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependencies: [] 3 | 4 | galaxy_info: 5 | role_name: drupal 6 | author: geerlingguy 7 | description: Deploy or install Drupal on your servers. 8 | company: "Midwestern Mac, LLC" 9 | license: "license (BSD, MIT)" 10 | min_ansible_version: 2.10 11 | platforms: 12 | - name: Ubuntu 13 | versions: 14 | - all 15 | - name: Debian 16 | versions: 17 | - all 18 | galaxy_tags: 19 | - development 20 | - web 21 | - drupal 22 | - cms 23 | - php 24 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | #become: true 5 | 6 | environment: 7 | COMPOSER_MEMORY_LIMIT: '-1' 8 | 9 | vars_files: 10 | - test-vars.yml 11 | 12 | pre_tasks: 13 | - import_tasks: test-setup.yml 14 | 15 | roles: 16 | - name: geerlingguy.repo-remi 17 | when: ansible_os_family == 'RedHat' 18 | - role: geerlingguy.repo-dotdeb 19 | when: ansible_distribution == 'Debian' 20 | - role: geerlingguy.apache 21 | - role: geerlingguy.mysql 22 | - role: geerlingguy.php-versions 23 | - role: geerlingguy.php 24 | - role: geerlingguy.php-mysql 25 | - role: geerlingguy.git 26 | - role: geerlingguy.composer 27 | - role: geerlingguy.drupal 28 | -------------------------------------------------------------------------------- /molecule/default/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | #become: true 5 | 6 | vars_files: 7 | - test-vars.yml 8 | 9 | vars: 10 | # Deploy from the Drupal for Kubernetes example project. 11 | drupal_deploy: true 12 | drupal_deploy_repo: "https://github.com/geerlingguy/drupal-for-kubernetes.git" 13 | drupal_deploy_dir: /var/www/drupal 14 | drupal_domain: "test.pidramble.com" 15 | 16 | # Disable Composer-based codebase setup. 17 | drupal_build_composer_project: false 18 | drupal_build_composer: false 19 | drupal_composer_dependencies: [] 20 | 21 | pre_tasks: 22 | - import_tasks: test-setup.yml 23 | 24 | roles: 25 | - name: geerlingguy.repo-remi 26 | when: ansible_os_family == "RedHat" 27 | - role: geerlingguy.repo-dotdeb 28 | when: ansible_distribution == 'Debian' 29 | - role: geerlingguy.apache 30 | - role: geerlingguy.mysql 31 | - role: geerlingguy.php-versions 32 | - role: geerlingguy.php 33 | - role: geerlingguy.php-mysql 34 | - role: geerlingguy.git 35 | - role: geerlingguy.composer 36 | - role: geerlingguy.drush 37 | - role: geerlingguy.drupal 38 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | role_name_check: 1 3 | dependency: 4 | name: galaxy 5 | options: 6 | ignore-errors: true 7 | driver: 8 | name: docker 9 | platforms: 10 | - name: instance 11 | image: "geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux9}-ansible:latest" 12 | command: ${MOLECULE_DOCKER_COMMAND:-""} 13 | volumes: 14 | - /sys/fs/cgroup:/sys/fs/cgroup:rw 15 | cgroupns_mode: host 16 | privileged: true 17 | pre_build_image: true 18 | provisioner: 19 | name: ansible 20 | playbooks: 21 | converge: ${MOLECULE_PLAYBOOK:-converge.yml} 22 | -------------------------------------------------------------------------------- /molecule/default/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - src: geerlingguy.repo-remi 3 | - src: geerlingguy.repo-dotdeb 4 | - src: geerlingguy.apache 5 | - src: geerlingguy.apache-php-fpm 6 | - src: geerlingguy.nginx 7 | - src: geerlingguy.mysql 8 | - src: geerlingguy.postgresql 9 | - src: geerlingguy.php-versions 10 | - src: geerlingguy.php 11 | - src: geerlingguy.php-mysql 12 | - src: geerlingguy.php-pgsql 13 | - src: geerlingguy.git 14 | - src: geerlingguy.composer 15 | - src: geerlingguy.drush 16 | -------------------------------------------------------------------------------- /molecule/default/test-setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Update apt cache. 3 | apt: 4 | update_cache: true 5 | cache_valid_time: 600 6 | when: ansible_os_family == 'Debian' 7 | 8 | - name: Install curl (RHEL). 9 | dnf: 10 | name: curl 11 | allowerasing: true 12 | state: present 13 | when: ansible_os_family == 'RedHat' 14 | 15 | - name: Install dependencies. 16 | package: 17 | name: 18 | - curl 19 | - unzip 20 | - sendmail 21 | state: present 22 | -------------------------------------------------------------------------------- /molecule/default/test-vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | php_version: "8.1" 3 | php_enable_webserver: false 4 | php_enablerepo: "remi,remi-php81" 5 | php_enable_php_fpm: true 6 | php_fpm_listen: "127.0.0.1:9000" 7 | 8 | apache_mods_enabled: 9 | - expires 10 | - ssl 11 | - rewrite 12 | - proxy 13 | - proxy_fcgi 14 | apache_remove_default_vhost: true 15 | apache_vhosts: 16 | - servername: "{{ drupal_domain }}" 17 | serveralias: "www.{{ drupal_domain }}" 18 | documentroot: "{{ drupal_core_path }}" 19 | extra_parameters: | 20 | 21 | SetHandler "proxy:fcgi://{{ php_fpm_listen }}" 22 | 23 | 24 | mysql_python_package_debian: python3-mysqldb 25 | mysql_enablerepo: "remi" 26 | mysql_databases: 27 | - name: "{{ drupal_db_name }}" 28 | encoding: utf8mb4 29 | collation: utf8mb4_general_ci 30 | mysql_users: 31 | - name: "{{ drupal_db_user }}" 32 | host: "%" 33 | password: "{{ drupal_db_password }}" 34 | priv: "{{ drupal_db_name }}.*:ALL" 35 | -------------------------------------------------------------------------------- /tasks/backwards-compatibility.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Shims for Drupal VM backwards compatibility. To be removed by 2018. 3 | - name: build_makefile shim 4 | set_fact: 5 | drupal_build_makefile: "{{ build_makefile }}" 6 | when: build_makefile|default('') 7 | 8 | - name: build_composer shim 9 | set_fact: 10 | drupal_build_composer: "{{ build_composer }}" 11 | when: build_composer|default('') 12 | 13 | - name: build_composer_project shim 14 | set_fact: 15 | drupal_build_composer_project: "{{ build_composer_project }}" 16 | when: build_composer_project|default('') 17 | 18 | - name: install_site shim 19 | set_fact: 20 | drupal_install_site: "{{ install_site }}" 21 | when: install_site|default('') 22 | 23 | - name: drupalvm_database shim 24 | set_fact: 25 | drupal_db_backend: "{{ drupalvm_database }}" 26 | when: drupalvm_database|default('') 27 | -------------------------------------------------------------------------------- /tasks/build-composer-project.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Delete old /tmp/composer-project 3 | file: 4 | path: "/tmp/composer-project" 5 | state: absent 6 | when: not drupal_site_exists 7 | 8 | - name: Generate Drupal project with composer package in /tmp/composer-project (this may take a while). 9 | command: > 10 | {{ composer_path }} create-project 11 | {{ drupal_composer_project_package }} /tmp/composer-project 12 | {{ drupal_composer_project_options|default('--prefer-dist --no-interaction') }} 13 | when: not drupal_site_exists 14 | become: false 15 | environment: 16 | COMPOSER_PROCESS_TIMEOUT: 1200 17 | COMPOSER_MEMORY_LIMIT: '-1' 18 | 19 | - name: Ensure drupal_composer_install_dir directory has proper permissions. 20 | file: 21 | path: "{{ drupal_composer_install_dir }}" 22 | state: directory 23 | owner: "{{ drupal_core_owner }}" 24 | group: "{{ drupal_core_owner }}" 25 | mode: 0775 26 | when: not drupal_site_exists 27 | failed_when: false 28 | 29 | - name: Move Drupal project files to drupal_composer_install_dir (this may take a while). 30 | command: > 31 | cp -r /tmp/composer-project/. {{ drupal_composer_install_dir }}/ 32 | creates={{ drupal_core_path }}/index.php 33 | become: false 34 | when: not drupal_site_exists 35 | 36 | - name: Install dependencies with composer require (this may take a while). 37 | composer: 38 | command: require 39 | arguments: "{{ item }}" 40 | working_dir: "{{ drupal_composer_install_dir }}" 41 | with_items: "{{ drupal_composer_dependencies | default([]) }}" 42 | become: false 43 | environment: 44 | COMPOSER_PROCESS_TIMEOUT: 1200 45 | COMPOSER_MEMORY_LIMIT: '-1' 46 | -------------------------------------------------------------------------------- /tasks/build-composer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure drupal_composer_install_dir directory exists. 3 | file: 4 | path: "{{ drupal_composer_install_dir }}" 5 | state: directory 6 | mode: 0775 7 | become: false 8 | when: drupal_composer_path and not drupal_site_exists 9 | 10 | # Use copy-and-move to prevent issues in Windows with VirtualBox. See: 11 | # https://github.com/ansible/ansible/issues/9526#issuecomment-62336962 12 | - name: Copy composer.json into temporary location. 13 | copy: 14 | src: "{{ drupal_composer_path }}" 15 | dest: "/tmp/drupalvm-composer.json" 16 | mode: 0644 17 | when: drupal_composer_path and not drupal_site_exists 18 | become: false 19 | 20 | - name: Move composer.json into place. 21 | command: "mv /tmp/drupalvm-composer.json {{ drupal_composer_install_dir }}/composer.json" 22 | when: drupal_composer_path and not drupal_site_exists 23 | become: false 24 | 25 | - name: Run composer install (this may take a while). 26 | composer: 27 | command: install 28 | working_dir: "{{ drupal_composer_install_dir }}" 29 | when: not drupal_site_exists 30 | become: false 31 | 32 | - name: Install dependencies with composer require (this may take a while). 33 | composer: 34 | command: require 35 | arguments: "{{ item }}" 36 | working_dir: "{{ drupal_composer_install_dir }}" 37 | with_items: "{{ drupal_composer_dependencies | default([]) }}" 38 | become: false 39 | environment: 40 | COMPOSER_PROCESS_TIMEOUT: 1200 41 | COMPOSER_MEMORY_LIMIT: '-1' 42 | -------------------------------------------------------------------------------- /tasks/build-makefile.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Copy drush makefile into place. 3 | copy: 4 | src: "{{ drush_makefile_path }}" 5 | dest: /tmp/drupal.make.yml 6 | mode: 0644 7 | when: not drupal_site_exists 8 | 9 | - name: Ensure drupal_core_path directory exists. 10 | file: 11 | path: "{{ drupal_core_path }}" 12 | state: directory 13 | recurse: true 14 | mode: 0775 15 | become: false 16 | when: not drupal_site_exists 17 | 18 | - name: Generate Drupal site with drush makefile. 19 | command: > 20 | {{ drush_path }} make -y /tmp/drupal.make.yml {{ drush_make_options }} 21 | chdir={{ drupal_core_path }} 22 | when: not drupal_site_exists 23 | become: false 24 | 25 | - name: Check if a composer.json file is present. 26 | stat: "path={{ drupal_core_path }}/composer.json" 27 | register: drupal_core_composer_file 28 | when: not drupal_site_exists 29 | 30 | - name: Run composer install if composer.json is present. 31 | command: > 32 | composer install 33 | chdir={{ drupal_core_path }} 34 | when: not drupal_site_exists and drupal_core_composer_file.stat.exists 35 | become: false 36 | -------------------------------------------------------------------------------- /tasks/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure drupal_deploy_dir directory exists. 3 | file: 4 | path: "{{ drupal_deploy_dir }}" 5 | state: directory 6 | mode: 0775 7 | owner: "{{ drupal_core_owner }}" 8 | group: "{{ drupal_core_owner }}" 9 | when: drupal_composer_path and not drupal_site_exists 10 | 11 | - name: Check out Drupal to the docroot. 12 | git: 13 | repo: "{{ drupal_deploy_repo }}" 14 | version: "{{ drupal_deploy_version }}" 15 | update: "{{ drupal_deploy_update }}" 16 | force: true 17 | dest: "{{ drupal_deploy_dir }}" 18 | accept_hostkey: "{{ drupal_deploy_accept_hostkey }}" 19 | register: drupal_deploy_repo_updated 20 | notify: clear opcache 21 | become: "{{ drupal_core_owner_become }}" 22 | become_user: "{{ drupal_core_owner }}" 23 | 24 | - name: Check if a composer.json file is present. 25 | stat: "path={{ drupal_deploy_dir }}/composer.json" 26 | register: drupal_deploy_composer_file 27 | 28 | - name: Run composer install if composer.json is present. 29 | composer: 30 | command: install 31 | working_dir: "{{ drupal_deploy_dir }}" 32 | no_dev: "{{ drupal_composer_no_dev }}" 33 | when: 34 | - drupal_deploy_composer_file.stat.exists 35 | - drupal_deploy_composer_install 36 | become: "{{ drupal_core_owner_become }}" 37 | become_user: "{{ drupal_core_owner }}" 38 | -------------------------------------------------------------------------------- /tasks/install-site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check if site is already installed. 3 | command: "{{ drush_path }} --root={{ drupal_core_path }} status bootstrap" 4 | args: 5 | chdir: "{{ drupal_core_path }}" 6 | register: drupal_site_installed 7 | failed_when: "drupal_site_installed.stdout is undefined" 8 | changed_when: false 9 | become: false 10 | 11 | # See: https://www.drupal.org/node/2569365#comment-11680807 12 | - name: Configure database correctly if using PostgreSQL. 13 | command: psql -c "ALTER DATABASE {{ drupal_db_name }} SET bytea_output = 'escape';" 14 | when: "('Drupal bootstrap' not in drupal_site_installed.stdout) and (drupal_db_backend == 'pgsql')" 15 | become: true 16 | become_user: "{{ postgresql_user }}" 17 | # See: https://github.com/ansible/ansible/issues/16048#issuecomment-229012509 18 | vars: 19 | ansible_ssh_pipelining: true 20 | 21 | - name: Install Drupal with drush. 22 | command: > 23 | {{ drush_path }} site-install {{ drupal_install_profile | default('standard') }} -y 24 | --root={{ drupal_core_path }} 25 | --site-name="{{ drupal_site_name }}" 26 | --account-name="{{ drupal_account_name }}" 27 | --account-pass={{ drupal_account_pass }} 28 | --db-url={{ drupal_db_backend }}://{{ drupal_db_user }}:{{ drupal_db_password }}@{{ drupal_db_host }}/{{ drupal_db_name }} 29 | {{ drupal_site_install_extra_args | join(" ") }} 30 | args: 31 | chdir: "{{ drupal_core_path }}" 32 | notify: clear opcache 33 | when: "'Drupal bootstrap' not in drupal_site_installed.stdout" 34 | become: false 35 | 36 | - name: Install configured modules with drush. 37 | command: > 38 | {{ drush_path }} pm-enable -y {{ drupal_enable_modules | join(" ") }} 39 | --root={{ drupal_core_path }} 40 | args: 41 | chdir: "{{ drupal_core_path }}" 42 | when: ('Drupal bootstrap' not in drupal_site_installed.stdout) and drupal_enable_modules 43 | become: false 44 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Add backwards-compatibility shims. 3 | include_tasks: backwards-compatibility.yml 4 | 5 | - name: Check if Drupal is already set up. 6 | stat: "path={{ drupal_core_path }}/index.php" 7 | register: drupal_site 8 | ignore_errors: true 9 | 10 | - name: Define drush_path if it's not already defined. 11 | set_fact: 12 | drush_path: drush 13 | when: drush_path is not defined 14 | 15 | - name: Define drupal_site_exists. 16 | set_fact: 17 | drupal_site_exists: "{{ drupal_site.stat.exists|default(false) }}" 18 | 19 | # Deploy Drupal if configured. 20 | - include_tasks: deploy.yml 21 | when: drupal_deploy 22 | 23 | - name: Define drupal_deploy_updated 24 | set_fact: 25 | drupal_deploy_updated: "{{ (drupal_deploy_repo_updated is defined and drupal_deploy_repo_updated.changed) | default(false) }}" 26 | 27 | # Run update tasks if Drupal was updated. 28 | - include_tasks: update.yml 29 | when: drupal_deploy_updated and drupal_site_exists 30 | 31 | # Build makefile if configured. 32 | - include_tasks: build-makefile.yml 33 | when: drupal_build_makefile 34 | 35 | # Build with composer if configured. 36 | - include_tasks: build-composer.yml 37 | when: drupal_build_composer 38 | 39 | # Build a composer project if configured. 40 | - include_tasks: build-composer-project.yml 41 | when: drupal_build_composer_project 42 | 43 | # Set Drush variables. 44 | - name: Check if a project specific Drush binary exists. 45 | stat: "path={{ drupal_composer_install_dir }}/{{ drupal_composer_bin_dir }}/drush" 46 | register: drush_vendor_bin 47 | ignore_errors: true 48 | 49 | - name: Use project specific Drush if available. 50 | set_fact: 51 | drush_path: "{{ drupal_composer_install_dir }}/{{ drupal_composer_bin_dir }}/drush" 52 | when: drush_vendor_bin.stat.exists 53 | 54 | # Install site if configured. 55 | - include_tasks: install-site.yml 56 | when: drupal_install_site 57 | -------------------------------------------------------------------------------- /tasks/update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Run database updates. 3 | command: "{{ drush_path }} updatedb -y" 4 | args: 5 | chdir: "{{ drupal_core_path }}" 6 | register: drush_database_updates 7 | changed_when: "'No database updates required.' not in drush_database_updates.stdout" 8 | 9 | # TODO: Import configuration if configured? 10 | # TODO: Other commands if configured? 11 | 12 | - name: Rebuild Drupal caches. 13 | command: "{{ drush_path }} cache-rebuild --quiet" 14 | args: 15 | chdir: "{{ drupal_core_path }}" 16 | tags: ['skip_ansible_lint'] 17 | --------------------------------------------------------------------------------