diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 223cec4..0000000 --- a/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/node_modules/ - diff --git a/dist/deploying-drupal-fabric/2017-10-20-drupalcamp-dublin/slides.pdf b/dist/deploying-drupal-fabric/2017-10-20-drupalcamp-dublin/slides.pdf deleted file mode 100644 index 2271ee8..0000000 Binary files a/dist/deploying-drupal-fabric/2017-10-20-drupalcamp-dublin/slides.pdf and /dev/null differ diff --git a/dist/deploying-drupal-fabric/2017-10-26-drupal-somerset/slides.pdf b/dist/deploying-drupal-fabric/2017-10-26-drupal-somerset/slides.pdf deleted file mode 100644 index e6f3ba4..0000000 Binary files a/dist/deploying-drupal-fabric/2017-10-26-drupal-somerset/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-ansible-ansistrano/2019-01-22-drupal-bristol/slides.pdf b/dist/deploying-php-ansible-ansistrano/2019-01-22-drupal-bristol/slides.pdf deleted file mode 100644 index 36eead5..0000000 Binary files a/dist/deploying-php-ansible-ansistrano/2019-01-22-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-ansible-ansistrano/2019-07-23-php-south-wales/slides.pdf b/dist/deploying-php-ansible-ansistrano/2019-07-23-php-south-wales/slides.pdf deleted file mode 100644 index a851668..0000000 Binary files a/dist/deploying-php-ansible-ansistrano/2019-07-23-php-south-wales/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-ansible-ansistrano/2019-10-30-drupalcon-amsterdam/slides.pdf b/dist/deploying-php-ansible-ansistrano/2019-10-30-drupalcon-amsterdam/slides.pdf deleted file mode 100644 index a59e667..0000000 Binary files a/dist/deploying-php-ansible-ansistrano/2019-10-30-drupalcon-amsterdam/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-ansible-ansistrano/2020-01-30-bristol-cloud-native-devops/slides.pdf b/dist/deploying-php-ansible-ansistrano/2020-01-30-bristol-cloud-native-devops/slides.pdf deleted file mode 100644 index e653639..0000000 Binary files a/dist/deploying-php-ansible-ansistrano/2020-01-30-bristol-cloud-native-devops/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-ansible-ansistrano/2020-05-01-cms-philly.pdf b/dist/deploying-php-ansible-ansistrano/2020-05-01-cms-philly.pdf deleted file mode 100644 index c656848..0000000 Binary files a/dist/deploying-php-ansible-ansistrano/2020-05-01-cms-philly.pdf and /dev/null differ diff --git a/dist/deploying-php-fabric/2017-04-20-nomad-php/slides.pdf b/dist/deploying-php-fabric/2017-04-20-nomad-php/slides.pdf deleted file mode 100644 index 197637b..0000000 Binary files a/dist/deploying-php-fabric/2017-04-20-nomad-php/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-fabric/2017-09-13-phpsw/slides.pdf b/dist/deploying-php-fabric/2017-09-13-phpsw/slides.pdf deleted file mode 100644 index f1a7ec1..0000000 Binary files a/dist/deploying-php-fabric/2017-09-13-phpsw/slides.pdf and /dev/null differ diff --git a/dist/deploying-php-fabric/2017-10-01-phpnw/slides.pdf b/dist/deploying-php-fabric/2017-10-01-phpnw/slides.pdf deleted file mode 100644 index e100772..0000000 Binary files a/dist/deploying-php-fabric/2017-10-01-phpnw/slides.pdf and /dev/null differ diff --git a/dist/drupal-8/2015-04-08-phpsw/slides.pdf b/dist/drupal-8/2015-04-08-phpsw/slides.pdf deleted file mode 100644 index 4070ea0..0000000 Binary files a/dist/drupal-8/2015-04-08-phpsw/slides.pdf and /dev/null differ diff --git a/dist/drupal-rejoining-php-herd/2016-06-11-php-south-coast/slides.pdf b/dist/drupal-rejoining-php-herd/2016-06-11-php-south-coast/slides.pdf deleted file mode 100644 index 419c83f..0000000 Binary files a/dist/drupal-rejoining-php-herd/2016-06-11-php-south-coast/slides.pdf and /dev/null differ diff --git a/dist/drupal-testing-workshop/2018-06-28-drupal-bristol/slides.pdf b/dist/drupal-testing-workshop/2018-06-28-drupal-bristol/slides.pdf deleted file mode 100644 index c19b548..0000000 Binary files a/dist/drupal-testing-workshop/2018-06-28-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/drupal-testing-workshop/2018-09-19-microserve/slides.pdf b/dist/drupal-testing-workshop/2018-09-19-microserve/slides.pdf deleted file mode 100644 index e4dec79..0000000 Binary files a/dist/drupal-testing-workshop/2018-09-19-microserve/slides.pdf and /dev/null differ diff --git a/dist/drupal-vm-generator/2016-04-02-drupal-bristol/slides.pdf b/dist/drupal-vm-generator/2016-04-02-drupal-bristol/slides.pdf deleted file mode 100644 index d4a53d3..0000000 Binary files a/dist/drupal-vm-generator/2016-04-02-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/drupal-vm-symfony-console/2016-07-23-drupalcamp-bristol/slides.pdf b/dist/drupal-vm-symfony-console/2016-07-23-drupalcamp-bristol/slides.pdf deleted file mode 100644 index 3582de4..0000000 Binary files a/dist/drupal-vm-symfony-console/2016-07-23-drupalcamp-bristol/slides.pdf and /dev/null differ diff --git a/dist/drush-make-drupal-bristol/2014-07-02-drupal-bristol/slides.pdf b/dist/drush-make-drupal-bristol/2014-07-02-drupal-bristol/slides.pdf deleted file mode 100644 index dc4c74c..0000000 Binary files a/dist/drush-make-drupal-bristol/2014-07-02-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/getting-started-drupal-8-module-development/2016-03-05-drupalcamp-london/slides.pdf b/dist/getting-started-drupal-8-module-development/2016-03-05-drupalcamp-london/slides.pdf deleted file mode 100644 index 1ce47be..0000000 Binary files a/dist/getting-started-drupal-8-module-development/2016-03-05-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/getting-your-data-into-drupal-8/2017-03-04-drupalcamp-london/slides.pdf b/dist/getting-your-data-into-drupal-8/2017-03-04-drupalcamp-london/slides.pdf deleted file mode 100644 index 45a9e8c..0000000 Binary files a/dist/getting-your-data-into-drupal-8/2017-03-04-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/getting-your-data-into-drupal-8/todo.md b/dist/getting-your-data-into-drupal-8/todo.md deleted file mode 100644 index c4dead5..0000000 --- a/dist/getting-your-data-into-drupal-8/todo.md +++ /dev/null @@ -1,5 +0,0 @@ -- Demonstrate plugins -- Writing own source/process plugins -- Core source plugins (Drupal to Drupal) -- Demo `hook_migrate_prepare_row()` and - `hook_migrate_MIGRATION_ID_prepare_row()` diff --git a/dist/git-flow/2014-03-01-drupalcamp-london/slides.pdf b/dist/git-flow/2014-03-01-drupalcamp-london/slides.pdf deleted file mode 100644 index f368c18..0000000 Binary files a/dist/git-flow/2014-03-01-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/goodbye-drush-make-hello-composer/2017-11-17-drupal-bristol/slides.pdf b/dist/goodbye-drush-make-hello-composer/2017-11-17-drupal-bristol/slides.pdf deleted file mode 100644 index 3e91556..0000000 Binary files a/dist/goodbye-drush-make-hello-composer/2017-11-17-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/goodbye-drush-make-hello-composer/2018-02-16-php-uk/slides.pdf b/dist/goodbye-drush-make-hello-composer/2018-02-16-php-uk/slides.pdf deleted file mode 100644 index e016925..0000000 Binary files a/dist/goodbye-drush-make-hello-composer/2018-02-16-php-uk/slides.pdf and /dev/null differ diff --git a/dist/having-fun-drupal-8-drupalorg-api/2018-04-18-drupal-bristol/slides.pdf b/dist/having-fun-drupal-8-drupalorg-api/2018-04-18-drupal-bristol/slides.pdf deleted file mode 100644 index b8ffe0e..0000000 Binary files a/dist/having-fun-drupal-8-drupalorg-api/2018-04-18-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/having-fun-drupal-8-drupalorg-api/2019-03-03-drupalcamp-london/slides.pdf b/dist/having-fun-drupal-8-drupalorg-api/2019-03-03-drupalcamp-london/slides.pdf deleted file mode 100644 index 11d1b67..0000000 Binary files a/dist/having-fun-drupal-8-drupalorg-api/2019-03-03-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/it-all-started-with-a-patch/2017-02-08-phpsw/slides.pdf b/dist/it-all-started-with-a-patch/2017-02-08-phpsw/slides.pdf deleted file mode 100644 index 711a9bf..0000000 Binary files a/dist/it-all-started-with-a-patch/2017-02-08-phpsw/slides.pdf and /dev/null differ diff --git a/dist/modern-drupal-development-composer/2016-11-09-phpsw/slides.pdf b/dist/modern-drupal-development-composer/2016-11-09-phpsw/slides.pdf deleted file mode 100644 index d287933..0000000 Binary files a/dist/modern-drupal-development-composer/2016-11-09-phpsw/slides.pdf and /dev/null differ diff --git a/dist/static-websites-sculpin/2015-10-14-phpsw/slides.pdf b/dist/static-websites-sculpin/2015-10-14-phpsw/slides.pdf deleted file mode 100644 index 3bb4265..0000000 Binary files a/dist/static-websites-sculpin/2015-10-14-phpsw/slides.pdf and /dev/null differ diff --git a/dist/taking-flight-with-tailwind-css/2018-01-17-drupal-bristol/slides.pdf b/dist/taking-flight-with-tailwind-css/2018-01-17-drupal-bristol/slides.pdf deleted file mode 100644 index 404deb0..0000000 Binary files a/dist/taking-flight-with-tailwind-css/2018-01-17-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/taking-flight-with-tailwind-css/2018-07-31-php-south-wales/slides.pdf b/dist/taking-flight-with-tailwind-css/2018-07-31-php-south-wales/slides.pdf deleted file mode 100644 index 72a71d9..0000000 Binary files a/dist/taking-flight-with-tailwind-css/2018-07-31-php-south-wales/slides.pdf and /dev/null differ diff --git a/dist/taking-flight-with-tailwind-css/2019-05-18-wordcamp-bristol/slides.pdf b/dist/taking-flight-with-tailwind-css/2019-05-18-wordcamp-bristol/slides.pdf deleted file mode 100644 index 96b113f..0000000 Binary files a/dist/taking-flight-with-tailwind-css/2019-05-18-wordcamp-bristol/slides.pdf and /dev/null differ diff --git a/dist/taking-flight-with-tailwind-css/2020-05-01-cms-philly.pdf b/dist/taking-flight-with-tailwind-css/2020-05-01-cms-philly.pdf deleted file mode 100644 index cd8b8f6..0000000 Binary files a/dist/taking-flight-with-tailwind-css/2020-05-01-cms-philly.pdf and /dev/null differ diff --git a/dist/test-drive-twig-sculpin/2015-07-25-drupalcamp-north/slides.pdf b/dist/test-drive-twig-sculpin/2015-07-25-drupalcamp-north/slides.pdf deleted file mode 100644 index 07d7abf..0000000 Binary files a/dist/test-drive-twig-sculpin/2015-07-25-drupalcamp-north/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2017-03-04-drupalcamp-london/slides.pdf b/dist/test-driven-drupal/2017-03-04-drupalcamp-london/slides.pdf deleted file mode 100644 index 3f2f160..0000000 Binary files a/dist/test-driven-drupal/2017-03-04-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2017-10-21-drupalcamp-dublin/slides.pdf b/dist/test-driven-drupal/2017-10-21-drupalcamp-dublin/slides.pdf deleted file mode 100644 index e0f910a..0000000 Binary files a/dist/test-driven-drupal/2017-10-21-drupalcamp-dublin/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2017-11-22-drupal-bristol/slides.pdf b/dist/test-driven-drupal/2017-11-22-drupal-bristol/slides.pdf deleted file mode 100644 index 7fe350e..0000000 Binary files a/dist/test-driven-drupal/2017-11-22-drupal-bristol/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2018-06-14-drupal-somerset/slides.pdf b/dist/test-driven-drupal/2018-06-14-drupal-somerset/slides.pdf deleted file mode 100644 index c6c4eaf..0000000 Binary files a/dist/test-driven-drupal/2018-06-14-drupal-somerset/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2018-07-05-drupal-dev-days/slides.pdf b/dist/test-driven-drupal/2018-07-05-drupal-dev-days/slides.pdf deleted file mode 100644 index 70a1135..0000000 Binary files a/dist/test-driven-drupal/2018-07-05-drupal-dev-days/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2019-03-02-drupalcamp-london/slides.pdf b/dist/test-driven-drupal/2019-03-02-drupalcamp-london/slides.pdf deleted file mode 100644 index 220faf5..0000000 Binary files a/dist/test-driven-drupal/2019-03-02-drupalcamp-london/slides.pdf and /dev/null differ diff --git a/dist/test-driven-drupal/2020-05-12-nwdug.pdf b/dist/test-driven-drupal/2020-05-12-nwdug.pdf deleted file mode 100644 index da34fb4..0000000 Binary files a/dist/test-driven-drupal/2020-05-12-nwdug.pdf and /dev/null differ diff --git a/dist/using-laravel-collections-outside-laravel/2017-12-21-nomad-php/slides.pdf b/dist/using-laravel-collections-outside-laravel/2017-12-21-nomad-php/slides.pdf deleted file mode 100644 index 1886054..0000000 Binary files a/dist/using-laravel-collections-outside-laravel/2017-12-21-nomad-php/slides.pdf and /dev/null differ diff --git a/dist/using-laravel-collections-outside-laravel/2018-08-28-php-south-wales/slides.pdf b/dist/using-laravel-collections-outside-laravel/2018-08-28-php-south-wales/slides.pdf deleted file mode 100644 index 6b9bbfe..0000000 Binary files a/dist/using-laravel-collections-outside-laravel/2018-08-28-php-south-wales/slides.pdf and /dev/null differ diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 870d78e..0000000 --- a/package-lock.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index 264121d..0000000 --- a/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "prettier": "^1.19.1" - } -} diff --git a/prettier.config.js b/prettier.config.js deleted file mode 100644 index 181b27c..0000000 --- a/prettier.config.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = { - arrowParens: 'avoid', - bracketSpacing: false, - endOfLine: 'lf', - htmlWhitespaceSensitivity: 'css', - insertPragma: false, - jsxBracketSameLine: false, - jsxSingleQuote: false, - printWidth: 80, - proseWrap: 'always', - quoteProps: 'as-needed', - requirePragma: false, - semi: false, - singleQuote: true, - tabWidth: 2, - trailingComma: 'all', - useTabs: false, -} diff --git a/src/deploying-drupal-ansible-ansistrano/demo.mp4 b/src/deploying-drupal-ansible-ansistrano/demo.mp4 deleted file mode 100644 index 2441483..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/demo.mp4 and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/after-provision-1.png b/src/deploying-drupal-ansible-ansistrano/images/after-provision-1.png deleted file mode 100644 index 85861af..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/after-provision-1.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/after-provision-2.png b/src/deploying-drupal-ansible-ansistrano/images/after-provision-2.png deleted file mode 100644 index b577f0f..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/after-provision-2.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/ansible.png b/src/deploying-drupal-ansible-ansistrano/images/ansible.png deleted file mode 100644 index c72d308..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/ansible.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/ansistrano-flow.png b/src/deploying-drupal-ansible-ansistrano/images/ansistrano-flow.png deleted file mode 100644 index 519adaf..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/ansistrano-flow.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/ansistrano.png b/src/deploying-drupal-ansible-ansistrano/images/ansistrano.png deleted file mode 100644 index 2954d3d..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/ansistrano.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/composer.png b/src/deploying-drupal-ansible-ansistrano/images/composer.png deleted file mode 100644 index bb95a49..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/composer.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/contribution.jpg b/src/deploying-drupal-ansible-ansistrano/images/drupalcon/contribution.jpg deleted file mode 100644 index ed5a478..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/contribution.jpg and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/feedback.jpg b/src/deploying-drupal-ansible-ansistrano/images/drupalcon/feedback.jpg deleted file mode 100644 index 8795c55..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/feedback.jpg and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/site.png b/src/deploying-drupal-ansible-ansistrano/images/drupalcon/site.png deleted file mode 100644 index c2d9b07..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/drupalcon/site.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/druplicon.png b/src/deploying-drupal-ansible-ansistrano/images/druplicon.png deleted file mode 100644 index b2cc145..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/druplicon.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-acquia.png b/src/deploying-drupal-ansible-ansistrano/images/logo-acquia.png deleted file mode 100644 index 233b6b5..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-acquia.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-digital-ocean.png b/src/deploying-drupal-ansible-ansistrano/images/logo-digital-ocean.png deleted file mode 100644 index 90c76b4..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-digital-ocean.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-linode.png b/src/deploying-drupal-ansible-ansistrano/images/logo-linode.png deleted file mode 100644 index 22daa66..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-linode.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-pantheon.png b/src/deploying-drupal-ansible-ansistrano/images/logo-pantheon.png deleted file mode 100644 index 966a3ac..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-pantheon.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-platformsh.png b/src/deploying-drupal-ansible-ansistrano/images/logo-platformsh.png deleted file mode 100644 index 7bde895..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-platformsh.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/logo-vultr.png b/src/deploying-drupal-ansible-ansistrano/images/logo-vultr.png deleted file mode 100644 index 9f79890..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/logo-vultr.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/site.png b/src/deploying-drupal-ansible-ansistrano/images/site.png deleted file mode 100644 index 7173f99..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/site.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/images/vagrant.png b/src/deploying-drupal-ansible-ansistrano/images/vagrant.png deleted file mode 100644 index 8636216..0000000 Binary files a/src/deploying-drupal-ansible-ansistrano/images/vagrant.png and /dev/null differ diff --git a/src/deploying-drupal-ansible-ansistrano/slides.md b/src/deploying-drupal-ansible-ansistrano/slides.md deleted file mode 100644 index f87cf2d..0000000 --- a/src/deploying-drupal-ansible-ansistrano/slides.md +++ /dev/null @@ -1,964 +0,0 @@ -autoscale: true -build-lists: true -code: line-height(1.2) -header-emphasis: #53B0EB -text: alignment(left) -theme: simple, 8 - -# [fit] **Deploying PHP applications**
using Ansible, Ansible Vault
and Ansistrano - -^ I work primarily with PHP, and there will be some PHP-isms in this talk (LAMP -stack, Composer). Will be using a Drupal 8 application as the example, but the -tools are tool and language agnostic. - ---- - -## **What we'll be looking at** - -- **Ansible** crash course -- Keeping secrets with **Ansible Vault** -- Deployments with **Ansistrano** - ---- - -[.build-lists: false][.header: #111111] - -![right 500%](../images/me-phpnw-inviqa.jpg) - -- Full Stack Software Developer & System Administrator -- **Senior Software Engineer** at **Inviqa** -- Acquia certified **Drupal 8 Grand Master** and **Cloud Pro** -- Open sourcer -- Drupal 7 & 8 **core contributor** -- @opdavies -- www.oliverdavies.uk - -^ Maintain Drupal modules, PHP CLI tools and libraries, Ansible roles Blog on my -website I work primarily with Drupal and Symfony I work for Inviqa, but this -based on my personal and side projects. I've been using Ansible for a number of -years, initially only for provisioning and setting up my laptop, and later for -application deployments - ---- - -![350% inline](images/logo-platformsh.png) -![150% inline](images/logo-acquia.png) ![130% inline](images/logo-pantheon.png) - -^ Large, well-known managed hosting companies Optimised servers for PHP/Drupal -applications Include some sort of deployment system This workflow doesn't apply -to this scenario - ---- - -![100%](images/logo-digital-ocean.png) ![30%](images/logo-linode.png) -![30%](images/logo-vultr.png) - -^ More applicable to virtual or dedicated servers with no existing deployment -process Not enough budget for fully-managed, or using internal infrastructure -This is where the this workflow would be useful - ---- - -# **What is Ansible?** - ---- - -## Ansible is an open-source **software provisioning, configuration management, and application-deployment** tool. - -![10% right](images/ansible.png) - -[.footer: https://en.wikipedia.org/wiki/Ansible_(software)] - ---- - -![10% right](images/ansible.png) - -### **What is Ansible?** - -- CLI tool -- Written in Python -- Configured with YAML -- Executes ad-hoc remote commands -- Installs software packages -- Performs deployment steps -- Batteries included - -^ Written in Python but you don't need to write or know Python to use it Drupal, -Symfony and a lot of other projects use YAML First-party modules (SSH keys, file -and directory management, package repositories, stopping/starting/restarting -services, DO/Linode/AWS integration) - ---- - -![10% right](images/ansible.png) - -### **What is Ansible?** - -- Hosts/Inventories -- Commands -- Playbooks -- Tasks -- Roles - -^ Hosts: where your managed nodes/hosts are. Can be static or dynamic. Commands: -run from a control node onto managed nodes Playbooks and Tasks: YAML -representation of a series of commands/steps - ---- - -![10% right](images/ansible.png) - -### **Why Ansible?** - -- Familiar syntax -- Easily readable -- No server dependencies -- Easy to add to an existing project -- Includes relevant modules (e.g. Composer) -- Idempotency - -^ Drupal 8, Symfony, Ansible all use YAML Runs on any server with Python Plugins -into Drupal via CLI apps like Drush and Drupal Console Changes are only made -when needed (once) - ---- - -# **Hosts / Inventories** - ---- - -```ini -# hosts.ini - -[webservers] -192.168.33.10 - -[webservers:vars] -ansible_ssh_port=22 - -``` - -^ Supports wildcards and ranges. - ---- - -```yaml -# hosts.yml - -all: - children: - webservers: - hosts: - 192.168.33.10: - vars: - ansible_ssh_port: 22 -``` - ---- - -# **Commands** - ---- - -# `ansible all -i hosts.yml -m ping` - ---- - -```json -webservers | SUCCESS => { - "ansible_facts": { - "discovered_interpreter_python": "/usr/bin/python" - }, - "changed": false, - "ping": "pong" -} -``` - ---- - -# `ansible all`
`-i hosts.yml`
`-m command`
`-a 'git pull`
`--chdir=/app'` - ---- - -# `ansible all -i hosts.yml`
`-m git -a 'repo=https://github.com/opdavies/dransible dest=/app`' - ---- - -# **Tasks and Playbooks** - ---- - -```yaml -# playbook.yml ---- -- hosts: webservers # or 'all' - - vars: - git_repo: https://github.com/opdavies/dransible - - tasks: - - name: Update the code - git: - repo: '{{ git_repo }}' - dest: /app - version: master - update: true -``` - ---- - -# `ansible-playbook`
`playbook.yml -i hosts.yml` - ---- - -# **Roles:
configuring a LAMP stack** - -^ Collections of tasks, variables and handlers - ---- - -```yaml -# requirements.yml ---- -- src: geerlingguy.apache -- src: geerlingguy.composer -- src: geerlingguy.mysql -- src: geerlingguy.php -- src: geerlingguy.php-mysql -``` - -^ Provisioning LAMP stack and Composer - ---- - -# `ansible-galaxy -r`
`requirements.yml install` - ---- - -```yaml -# provision.yml ---- -- hosts: webservers - - roles: - - geerlingguy.apache - - geerlingguy.mysql - - geerlingguy.php - - geerlingguy.php-mysql - - geerlingguy.composer -``` - -^ Role order matters! - ---- - -```yaml -# provision.yml ---- -- hosts: webservers - # ... - - vars: - apache_vhosts: - - servername: dransible.wip - documentroot: /app/web -``` - ---- - -```yaml -# provision.yml ---- -- hosts: webservers - # ... - - vars: - # ... - php_version: '7.4' - php_packages_extra: - - libapache2-mod-php{{ php_version }} - - libpcre3-dev -``` - ---- - -```yaml -# provision.yml ---- -- hosts: webservers - # ... - - vars: - # ... - mysql_databases: - - name: main - - mysql_users: - - name: user - password: secret - priv: main.*:ALL -``` - ---- - -# `ansible-playbook provision.yml -i hosts.yml` - ---- - -``` -PLAY [Provision the webserver machines] ******************************************************************************** - -TASK [Gathering Facts] ************************************************************************************************* -ok: [webservers] - -TASK [geerlingguy.apache : Include OS-specific variables.] ************************************************************* -ok: [webservers] - -TASK [geerlingguy.apache : Include variables for Amazon Linux.] -skipping: [webservers] - -TASK [geerlingguy.apache : Define apache_packages.] ******************************************************************** -ok: [webservers] - -TASK [geerlingguy.apache : include_tasks] ****************************************************************************** -included: /Users/opdavies/.ansible/roles/geerlingguy.apache/tasks/setup-Debian.yml for webservers - -TASK [geerlingguy.apache : Update apt cache.] ************************************************************************** -changed: [webservers] -``` - ---- - -``` -TASK [geerlingguy.composer : Ensure composer directory exists.] ******************************************************** -ok: [webservers] - -TASK [geerlingguy.composer : include_tasks] **************************************************************************** -skipping: [webservers] - -TASK [geerlingguy.composer : include_tasks] **************************************************************************** -skipping: [webservers] - -RUNNING HANDLER [geerlingguy.apache : restart apache] ****************************************************************** -changed: [webservers] - -RUNNING HANDLER [geerlingguy.mysql : restart mysql] ******************************************************************** -changed: [webservers] - -RUNNING HANDLER [geerlingguy.php : restart webserver] ****************************************************************** -changed: [webservers] - -RUNNING HANDLER [geerlingguy.php : restart php-fpm] ******************************************************************** -skipping: [webservers] - -PLAY RECAP ************************************************************************************************************* -webservers : ok=111 changed=32 unreachable=0 failed=0 skipped=78 rescued=0 ignored=0 -``` - ---- - -![70%](images/after-provision-1.png) - ---- - -![70%](images/after-provision-2.png) - ---- - -# **Keeping secrets with
Ansible Vault** - ---- - -```yaml -# provision.yml ---- -- hosts: webservers - # ... - - vars: - # ... - mysql_databases: - - name: main - - mysql_users: - - name: user - password: secret - priv: main.*:ALL -``` - ---- - -[.code-highlight: 11-14] - -```yaml -# provision.yml ---- -- hosts: webservers - # ... - - vars: - # ... - mysql_databases: - - name: main - - mysql_users: - - name: user - password: secret - priv: main.*:ALL -``` - ---- - -# `ansible-vault create`
`vault.yml` - ---- - -```yaml -# vars/vault.yml ---- -vault_database_name: main -vault_database_user: user -vault_database_password: secret -``` - -^ Optional, but easier to see where variables are set - ---- - -``` -$ANSIBLE_VAULT;1.1;AES256 -36656233323539616336393838396137343939623233393338666530313 -73037323366326363306531336333353163643063663335396139363762 -39383133330a35636566623262353733373066363837393264616134613 -16366376266646437373366373738303931616333626332353839353332 -32663432346662613438330a38643539343232376138613733373636343 -63864666430313866623539333039363138646331326565386263386666 -35306264396230633939346532356665306564626431353936643135376 -23834346635366637613235656165643361316663396530383263333064 -33326264316235396431666262346637366563376330363238373331373 -43533386165366531626462643662666266316639306262666539373236 -343662313265376261316636623963353933613366353737363435 -``` - ---- - -```yaml -# vars/vars.yml ---- -database_name: '{{ vault_database_name }}' -database_user: '{{ vault_database_user }}' -database_password: '{{ vault_database_password }}' -``` - ---- - -```yaml -# provision.yml ---- -mysql_databases: - - '{{ database_name }}' - -mysql_users: - - name: '{{ database_user }}' - password: '{{ database_password }}' - priv: '{{ database_name }}.*:ALL' -``` - ---- - -# `ansible-vault edit vault.yml` - ---- - -# `ansible-playbook`
`-i hosts.yml`
`deploy.yml`
`--ask-vault-pass` - ---- - -# `ansible-playbook`
`-i hosts.yml`
`deploy.yml`
`--vault-password-file secret.txt` - ---- - -# **Basic deployment** - ---- - -```yaml -# deploy.yml - -tasks: - - name: Creating project directory - file: - path: /app - state: directory - - - name: Uploading application - synchronize: - src: '{{ playbook_dir }}/../' - dest: /app - - - name: Installing Composer dependencies - composer: - command: install - working_dir: /app -``` - ---- - -# Disadvantages - -- Single point of failure -- No ability to roll back -- Sensitive data stored in plain text - ---- - -# **Better deployments** - ---- - -![full inline](images/ansistrano.png) - -^ Just another role, specifically for deployments Ansible port of Capistrano (Ruby) - ---- - -# Features - -- Multiple release directories -- Shared paths and files -- Customisable -- Multiple deployment strategies -- Multi-stage environments -- Prune old releases -- Rollbacks - -^ rsync, Git, SVN etc - ---- - -```yaml -# requirements.yml ---- -# ... -- ansistrano.deploy -- ansistrano.rollback -``` - ---- - -```yaml -# deploy.yml ---- -- hosts: all - - roles: - - ansistrano.deploy -``` - ---- - -```yaml -# deploy.yml ---- -# ... -vars: - project_deploy_dir: /app - - ansistrano_deploy_to: '{{ project_deploy_dir }}' - ansistrano_deploy_via: git - ansistrano_git_branch: master - ansistrano_git_repo: 'git@github.com:opdavies/dransible' -``` - ---- - -# `ansible-playbook`
`-i hosts.yml`
`deploy.yml` - ---- - -``` -PLAY [webservers] ****************************************************************************************************** - -TASK [Gathering Facts] ************************************************************************************************* -ok: [webservers] - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* -included: /Users/opdavies/.ansible/roles/ansistrano.deploy/tasks/setup.yml for webservers - -TASK [ansistrano.deploy : ANSISTRANO | Ensure deployment base path exists] ********************************************* -ok: [webservers] - -TASK [ansistrano.deploy : ANSISTRANO | Ensure releases folder exists] ************************************************** -ok: [webservers] - -TASK [ansistrano.deploy : ANSISTRANO | Ensure shared elements folder exists] ******************************************* -ok: [webservers] - -TASK [ansistrano.deploy : ANSISTRANO | Ensure shared paths exists] ***************************************************** -ok: [webservers] => (item=web/sites/default/files) -``` - ---- - -``` -TASK [ansistrano.deploy : Update file permissions] ********************************************************************* -changed: [webservers] - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* -included: /Users/opdavies/.ansible/roles/ansistrano.deploy/tasks/cleanup.yml for webservers - -TASK [ansistrano.deploy : ANSISTRANO | Clean up releases] ************************************************************** -changed: [webservers] - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* - -TASK [ansistrano.deploy : include_tasks] ******************************************************************************* -included: /Users/opdavies/.ansible/roles/ansistrano.deploy/tasks/anon-stats.yml for webservers - -TASK [ansistrano.deploy : ANSISTRANO | Send anonymous stats] *********************************************************** -skipping: [webservers] - -PLAY RECAP ************************************************************************************************************* -webservers : ok=33 changed=14 unreachable=0 failed=0 skipped=7 rescued=0 ignored=0 -``` - ---- - -```bash -vagrant@dransible:/app$ ls -l -total 8 - -lrwxrwxrwx 1 26 Jul 19 00:15 current -> ./releases/20190719001241Z -drwxr-xr-x 5 4096 Jul 22 20:30 releases -drwxr-xr-x 4 4096 Jul 19 00:00 shared -``` - ---- - -``` -vagrant@dransible:/app/releases$ ls -l -total 20 - -drwxr-xr-x 5 4096 Jul 22 20:30 . -drwxr-xr-x 4 4096 Jul 19 00:15 .. -drwxr-xr-x 10 4096 Jul 19 00:02 20190719000013Z -drwxr-xr-x 10 4096 Jul 19 00:14 20190719001241Z -drwxr-xr-x 9 4096 Jul 22 20:30 20190722203038Z -``` - ---- - -# `ansible-playbook`
`-i hosts.yml`
`rollback.yml` - ---- - -```yaml -# rollback.yml ---- -- hosts: all - - roles: - - ansistrano.rollback - - vars: - ansistrano_deploy_to: '{{ project_deploy_dir }}' -``` - ---- - -# **Customising Ansistrano:
Build Hooks** - ---- - -![inline 140%](images/ansistrano-flow.png) - -^ Shared = files directory, logs Before/after symlink shared = run tests Symlink -= 'current' symlink, site is live Clean up = remove node_modules, database -export, sqlite testing DB - ---- - -```yaml -# deploy.yml ---- -# ... - -ansistrano_after_symlink_shared_tasks_file: - '{{ playbook_dir }}/deploy/after-symlink-shared.yml' -ansistrano_after_symlink_tasks_file: - '{{ playbook_dir }}/deploy/after-symlink.yml' -ansistrano_after_update_code_tasks_file: - '{{ playbook_dir }}/deploy/after-update-code.yml' - -release_web_path: '{{ ansistrano_release_path.stdout }}/web' -release_drush_path: '{{ ansistrano_release_path.stdout }}/vendor/bin/drush' -``` - -^ Each step has a 'before' and 'after' step Ansistrano allows us to add more -things by providing a path to a playbook and adding additional steps. - ---- - -```yaml -# deploy/after-update-code.yml ---- -- name: Install Composer dependencies - composer: - command: install - working_dir: '{{ ansistrano_release_path.stdout }}' -``` - ---- - -```yaml -# deploy/after-symlink-shared.yml ---- -- name: Run database updates - command: '{{ release_drush_path }} --root {{ release_web_path }} updatedb' -``` - ---- - -```yaml -# deploy/after-symlink.yml ---- -- name: Clear Drupal cache - command: - '{{ release_drush_path }} --root {{ release_web_path }} cache-rebuild' -``` - ---- - -![80%](images/drupalcon/site.png) - ---- - -# **Managing data
across deployments** - ---- - -```yaml -# deploy.yml - -vars: - # ... - ansistrano_shared_paths: - - '{{ drupal_root }}/sites/default/files' -``` - ---- - -``` -vagrant@dransible:/app/shared/web/sites/default/files$ ls -la -total 28 - -drwxrwxrwx 6 4096 Jul 19 00:18 . -drwxr-xr-x 3 4096 Jul 19 00:00 .. -drwxrwxr-x 2 4096 Jul 22 21:24 css --rwxrwxrwx 1 487 Jul 19 00:02 .htaccess -drwxrwxr-x 2 4096 Jul 19 00:19 js -drwxrwxrwx 3 4096 Jul 19 00:18 php -drwxrwxrwx 2 4096 Jul 19 00:03 styles -``` - ---- - -``` -vagrant@dransible:/app/current/web/sites/default$ ls -la -total 48 -dr-xr-xr-x 2 4096 Jul 19 00:14 . -drwxr-xr-x 3 4096 Jan 22 17:30 .. --rw-r--r-- 1 6762 Jul 19 00:14 default.services.yml --rw-r--r-- 1 31342 Jul 19 00:14 default.settings.php -lrwxrwxrwx 1 45 Jul 19 00:14 files -> ../../../../../shared/web/sites/default/files --rw-r--r-- 1 35 Jul 19 00:12 settings.php -``` - ---- - -# **Generating settings
files per deployment** - ---- - -```yaml -# vars/vault.yml ---- -vault_database_name: main -vault_database_user: user -vault_database_password: secret -vault_hash_salt: dfgiy$fd2!34gsf2*34g74 -``` - ---- - -```yaml -# vars/vars.yml ---- -database_name: '{{ vault_database_name }}' -database_password: '{{ vault_database_password }}' -database_user: '{{ vault_database_user }}' -hash_salt: '{{ vault_hash_salt }}' -``` - ---- - -```yaml -# vars/vars.yml ---- -drupal_settings: - - drupal_root: /app/web - sites: - - name: default - settings: - databases: - default: - default: - driver: mysql - host: localhost - database: '{{ database_name }}' - username: '{{ database_user }}' - password: '{{ database_password }}' - hash_salt: '{{ hash_salt }}' - config_directories: - sync: ../config/sync -``` - ---- - -```php -// templates/settings.php.j2 - -// {{ ansible_managed }} - -{% for key, values in item.1.settings.databases.items() %} -{% for target, values in values.items() %} -$databases['{{ key }}']['{{ target }}'] = array( - 'driver' => '{{ values.driver|default('mysql') }}', - 'host' => '{{ values.host|default('localhost') }}', - 'database' => '{{ values.database }}', - 'username' => '{{ values.username }}', - 'password' => '{{ values.password }}', -); - -{% endfor %} -{% endfor %} - -{% if item.1.settings.base_url is defined %} -$base_url = '{{ item.1.settings.base_url }}'; -{% endif %} - -{# ... #} -``` - ---- - -```yaml -# tasks/main.yml ---- -- name: Ensure directory exists - file: - state: directory - path: '{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}' - with_subelements: - - '{{ drupal_settings }}' - - sites - no_log: true - -- name: Create settings files - template: - src: settings.php.j2 - dest: - '{{ item.0.drupal_root }}/sites/{{ item.1.name|default("default") }}/{{ - item.1.filename|default("settings.php") }}' - with_subelements: - - '{{ drupal_settings }}' - - sites - no_log: true -``` - ---- - -# **Multiple environments** - -## Dev, test, production - ---- - -```yaml -mysql_databases: - - name: production - - name: staging - -mysql_users: - - name: production - password: '{{ live_db_password }}' - priv: '{{ live_db_name }}.*:ALL' - - - name: staging - password: '{{ staging_db_password }}' - priv: staging.*:ALL -``` - ---- - -```yaml -# inventories/live.yml ---- -all: - hosts: - webservers: - ansible_ssh_host: 192.168.33.10 - ansible_ssh_port: 22 - - project_deploy_path: /app - git_branch: master - - drupal_hash_salt: '{{ vault_drupal_hash_salt }}' - drupal_install: true - - drupal_settings: - # ... -``` - ---- - -```yaml -# inventories/staging.yml ---- -all: - hosts: - webservers: - ansible_ssh_host: 192.168.33.10 - ansible_ssh_port: 22 - - project_deploy_path: /app-test - git_branch: develop - - drupal_hash_salt: '{{ vault_drupal_hash_salt }}' - drupal_install: true - - drupal_settings: - # ... -``` - ---- - -# `ansible-playbook deploy.yml -i inventories/staging.yml` - ---- - -# `ansible-playbook deploy.yml -i inventories/live.yml` - ---- - -# **Demo** - ---- - -# **Questions?** - -### oliverdavies.uk/dransible
@opdavies \ No newline at end of file diff --git a/src/drupal-testing-workshop/images/2c6qi8.jpg b/src/drupal-testing-workshop/images/2c6qi8.jpg deleted file mode 100644 index 93bd9a9..0000000 Binary files a/src/drupal-testing-workshop/images/2c6qi8.jpg and /dev/null differ diff --git a/src/drupal-testing-workshop/images/appnovation.png b/src/drupal-testing-workshop/images/appnovation.png deleted file mode 100644 index 49e432c..0000000 Binary files a/src/drupal-testing-workshop/images/appnovation.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/broadbean.png b/src/drupal-testing-workshop/images/broadbean.png deleted file mode 100644 index 3aaf673..0000000 Binary files a/src/drupal-testing-workshop/images/broadbean.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/collection-class-1.png b/src/drupal-testing-workshop/images/collection-class-1.png deleted file mode 100644 index 3c1d004..0000000 Binary files a/src/drupal-testing-workshop/images/collection-class-1.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/collection-class-2.png b/src/drupal-testing-workshop/images/collection-class-2.png deleted file mode 100644 index 09be34e..0000000 Binary files a/src/drupal-testing-workshop/images/collection-class-2.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-1.png b/src/drupal-testing-workshop/images/d8-simpletest-1.png deleted file mode 100644 index 5ef734a..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-1.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-2.png b/src/drupal-testing-workshop/images/d8-simpletest-2.png deleted file mode 100644 index 6a86356..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-2.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-3.png b/src/drupal-testing-workshop/images/d8-simpletest-3.png deleted file mode 100644 index 9f2e423..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-3.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-4.png b/src/drupal-testing-workshop/images/d8-simpletest-4.png deleted file mode 100644 index 162c867..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-4.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-5.png b/src/drupal-testing-workshop/images/d8-simpletest-5.png deleted file mode 100644 index 2e1e4fe..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-5.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-6.png b/src/drupal-testing-workshop/images/d8-simpletest-6.png deleted file mode 100644 index 33e29f6..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-6.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/d8-simpletest-7.png b/src/drupal-testing-workshop/images/d8-simpletest-7.png deleted file mode 100644 index 9b5463d..0000000 Binary files a/src/drupal-testing-workshop/images/d8-simpletest-7.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/dcbristol.png b/src/drupal-testing-workshop/images/dcbristol.png deleted file mode 100644 index 552904f..0000000 Binary files a/src/drupal-testing-workshop/images/dcbristol.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/deploy-all-the-things.jpg b/src/drupal-testing-workshop/images/deploy-all-the-things.jpg deleted file mode 100644 index f90028e..0000000 Binary files a/src/drupal-testing-workshop/images/deploy-all-the-things.jpg and /dev/null differ diff --git a/src/drupal-testing-workshop/images/files.png b/src/drupal-testing-workshop/images/files.png deleted file mode 100644 index a23b62a..0000000 Binary files a/src/drupal-testing-workshop/images/files.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/homer-smart.png b/src/drupal-testing-workshop/images/homer-smart.png deleted file mode 100644 index 50c5705..0000000 Binary files a/src/drupal-testing-workshop/images/homer-smart.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/kernel-tests.png b/src/drupal-testing-workshop/images/kernel-tests.png deleted file mode 100644 index 20921a7..0000000 Binary files a/src/drupal-testing-workshop/images/kernel-tests.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/matt-stauffer-tweet.png b/src/drupal-testing-workshop/images/matt-stauffer-tweet.png deleted file mode 100644 index 3f27a45..0000000 Binary files a/src/drupal-testing-workshop/images/matt-stauffer-tweet.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/me.jpg b/src/drupal-testing-workshop/images/me.jpg deleted file mode 100644 index 4b3e031..0000000 Binary files a/src/drupal-testing-workshop/images/me.jpg and /dev/null differ diff --git a/src/drupal-testing-workshop/images/phpstorm-integration.png b/src/drupal-testing-workshop/images/phpstorm-integration.png deleted file mode 100644 index c0d12c7..0000000 Binary files a/src/drupal-testing-workshop/images/phpstorm-integration.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/phpunit.png b/src/drupal-testing-workshop/images/phpunit.png deleted file mode 100644 index d22c405..0000000 Binary files a/src/drupal-testing-workshop/images/phpunit.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/simpletest-1.png b/src/drupal-testing-workshop/images/simpletest-1.png deleted file mode 100644 index 368de76..0000000 Binary files a/src/drupal-testing-workshop/images/simpletest-1.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/simpletest-2.png b/src/drupal-testing-workshop/images/simpletest-2.png deleted file mode 100644 index f823167..0000000 Binary files a/src/drupal-testing-workshop/images/simpletest-2.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/simpletest-3.png b/src/drupal-testing-workshop/images/simpletest-3.png deleted file mode 100644 index c413758..0000000 Binary files a/src/drupal-testing-workshop/images/simpletest-3.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/simpletest-4.png b/src/drupal-testing-workshop/images/simpletest-4.png deleted file mode 100644 index fcce824..0000000 Binary files a/src/drupal-testing-workshop/images/simpletest-4.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/simpletest.png b/src/drupal-testing-workshop/images/simpletest.png deleted file mode 100644 index 76c497c..0000000 Binary files a/src/drupal-testing-workshop/images/simpletest.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-blog-1.png b/src/drupal-testing-workshop/images/tdd-blog-1.png deleted file mode 100644 index ea4fdc0..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-blog-1.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-blog-2.png b/src/drupal-testing-workshop/images/tdd-blog-2.png deleted file mode 100644 index 3bce812..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-blog-2.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-blog-3.png b/src/drupal-testing-workshop/images/tdd-blog-3.png deleted file mode 100644 index 3b20e02..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-blog-3.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-blog-4.png b/src/drupal-testing-workshop/images/tdd-blog-4.png deleted file mode 100644 index 66a0b80..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-blog-4.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-blog-5.png b/src/drupal-testing-workshop/images/tdd-blog-5.png deleted file mode 100644 index b50dd8a..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-blog-5.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-circle-of-life.png b/src/drupal-testing-workshop/images/tdd-circle-of-life.png deleted file mode 100644 index 78e5f34..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-circle-of-life.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/tdd-loop.png b/src/drupal-testing-workshop/images/tdd-loop.png deleted file mode 100644 index ffd6078..0000000 Binary files a/src/drupal-testing-workshop/images/tdd-loop.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/timmillwood-ono.png b/src/drupal-testing-workshop/images/timmillwood-ono.png deleted file mode 100644 index be4eda4..0000000 Binary files a/src/drupal-testing-workshop/images/timmillwood-ono.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/title.png b/src/drupal-testing-workshop/images/title.png deleted file mode 100644 index 3110bf9..0000000 Binary files a/src/drupal-testing-workshop/images/title.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/toggle-optional-fields-1.png b/src/drupal-testing-workshop/images/toggle-optional-fields-1.png deleted file mode 100644 index 8378788..0000000 Binary files a/src/drupal-testing-workshop/images/toggle-optional-fields-1.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/toggle-optional-fields-2.png b/src/drupal-testing-workshop/images/toggle-optional-fields-2.png deleted file mode 100644 index 4112014..0000000 Binary files a/src/drupal-testing-workshop/images/toggle-optional-fields-2.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/toggle-optional-fields-3.png b/src/drupal-testing-workshop/images/toggle-optional-fields-3.png deleted file mode 100644 index 8339887..0000000 Binary files a/src/drupal-testing-workshop/images/toggle-optional-fields-3.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/toggle-optional-fields-button.png b/src/drupal-testing-workshop/images/toggle-optional-fields-button.png deleted file mode 100644 index 7f8db5f..0000000 Binary files a/src/drupal-testing-workshop/images/toggle-optional-fields-button.png and /dev/null differ diff --git a/src/drupal-testing-workshop/images/when-you-do-things-right.jpg b/src/drupal-testing-workshop/images/when-you-do-things-right.jpg deleted file mode 100644 index efe0ac4..0000000 Binary files a/src/drupal-testing-workshop/images/when-you-do-things-right.jpg and /dev/null differ diff --git a/src/drupal-testing-workshop/slides.md b/src/drupal-testing-workshop/slides.md deleted file mode 100644 index ba0adcf..0000000 --- a/src/drupal-testing-workshop/slides.md +++ /dev/null @@ -1,1361 +0,0 @@ -autoscale: true build-lists: true header-emphasis: #3D85C6 header: -alignment(left) text: alignment(left) text-emphasis: #3D85C6 theme: poster, 8 -code: Monaco, #6699FF, #999999, #6666FF, #66FF66, #66FF66, line-height(1.5) - -[.header: alignment(center)] - -![](../images/title.png) - -# [fit] Drupal Testing Workshop - -### _September 2018_ - ---- - -[.header: alignment(center)] - -## _Why_ write tests? - ---- - -## _Why write tests?_ - -- Catch bugs earlier -- Peace of mind -- Prevent regressions -- Write less code -- Documentation -- Drupal core requirement - __ -- More important with regular D8 releases - -^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst -developing rather than after it's been released) Refer to tests when writing -implementation code ONO merge conflict - ---- - -[.header: alignment(center)] - -## [fit] _Having tests does not mean_ - -## [fit] there will be no bugs - ---- - -[.header: alignment(center)] - -## [fit] _Testing may add time now_ - -## [fit] but save more time in the future - ---- - -## _Testing in Drupal_ - -- _Drupal 7_ - Simpletest (testing) module provided as part of core -- _Drupal 8_ - PHPUnit added as a core dependency -- _PHPUnit Initiative_ - Simpletest to be deprecated and removed - -^ Focussing on PHPUnit today - ---- - -[.header: #3D85C6] - -## Writing Tests (Drupal 8) - -- PHP class with _.php_ extension -- _tests/src_ directory within each module -- Within the _Drupal\Tests\module_name_ namespace -- Class name must match the filename -- Namespace must match the directory structure -- One test class per feature -- Each method must start with _test_ - -^ Different to D7 - ---- - -### _Exercise 1_ - -## Local site setup - ---- - -[.header: #3D85C6] - -## Docksal - -- Docker based local development environment -- Microserve standard -- Open source -- Per site configuration and customisation -- fin CLI, Apache, MySQL, Solr, Varnish, Mailhog, PHPMyAdmin etc -- Virtualbox or native Docker -- Can slow down tests -- Provides consistency - ---- - -- https://github.com/opdavies/drupal-testing-workshop -- https://docksal.io/installation -- git clone -- fin init -- http://drupaltest.docksal - -^ Contains Drupal 8 with Composer, examples module - ---- - -### _Exercise 2_ - -## Running Tests - ---- - -### _Option 1_ - -## Simpletest module (UI) - ---- - -![fit](../images/d8-simpletest-1.png) - ---- - -![fit](../images/d8-simpletest-2.png) - ---- - -![fit](../images/d8-simpletest-3.png) - ---- - -![fit](../images/d8-simpletest-4.png) - ---- - -![fit](../images/d8-simpletest-5.png) - ---- - -![fit](../images/d8-simpletest-6.png) - ---- - -![fit](../images/d8-simpletest-7.png) - ---- - -### _Option 2_ - -## Command line - ---- - -## Prerequisite _(creating a phpunit.xml file)_ - -- Configures PHPUnit -- Needed to run some types of tests -- Ignored by Git by default -- Copy _core/phpunit.xml.dist_ to _core/phpunit.xml_ -- Add and change as needed - - `SIMPLETEST_BASE_URL`, `SIMPLETEST_DB`, `BROWSERTEST_OUTPUT_DIRECTORY` - - `stopOnFailure="true"` - ---- - -``` -cd web - -../vendor/bin/phpunit -c core \ -modules/contrib/examples/phpunit_example -``` - ---- - -``` -cd web/core - -../../vendor/bin/phpunit \ -../modules/contrib/examples/phpunit_example -``` - ---- - -## Pro-tip: Add paths to _\$PATH_ - -```bash -# ~/.zshrc - -export PATH=$HOME/bin:/usr/local/bin:$PATH - -export PATH=vendor/bin:$PATH -export PATH=../vendor/bin:$PATH -export PATH=node_modules/.bin:$PATH -``` - ---- - -### _Option 2_ - -## CLI with Docksal - ---- - -``` -fin bash - -cd web - -../vendor/bin/phpunit -c core \ -modules/contrib/examples/phpunit_example -``` - ---- - -``` -fin bash - -cd web/core - -../../vendor/bin/phpunit \ -../modules/contrib/examples/phpunit_example -``` - ---- - -### _Option 3_ - -## Docksal PHPUnit addon - ---- - -- Custom Docksal command -- Submitted to the Docksal addons repo -- _fin addon install phpunit_ -- Wrapper around phpunit command -- Copies a stub phpunit.xml file if exists, or duplicates phpunit.xml.dist -- Shorter command, combines two actions - -^ Checks for core/phpunit.xml on each test run Will create one if is not present - ---- - -``` -fin phpunit web/modules/contrib/examples/phpunit_example -``` - ---- - -``` -Copying stubs from /var/www/.docksal/addons/phpunit/stubs -``` - ---- - -``` -PHPUnit 6.5.8 by Sebastian Bergmann and contributors. - -Testing web/modules/contrib/examples/phpunit_example -.................................. 34 / 34 (100%) - -Time: 46.8 seconds, Memory: 6.00MB - -OK (34 tests, 41 assertions) -``` - ---- - -``` -fin phpunit web/modules/contrib/examples/phpunit_example - - -Copying /var/www/web/core/phpunit.xml.dist to /var/www/web/core/phpunit.xml. -Please edit it's values as needed and re-run 'fin phpunit'. -``` - ---- - -``` -fin phpunit web/modules/contrib/examples/phpunit_example - - -PHPUnit 6.5.8 by Sebastian Bergmann and contributors. - -Testing web/modules/contrib/examples/phpunit_example -.................................. 34 / 34 (100%) - -Time: 48.62 seconds, Memory: 6.00MB - -OK (34 tests, 41 assertions) -``` - ---- - -### _Option 4_ - -## IDE/text editor integration - ---- - -![fit](../images/phpstorm-integration.png) - ---- - -[.header: alignment(center)] - -## Types of tests - ---- - -[.header: #3D85C6] - -## Functional tests - -- Tests functionality -- Interacts with database -- Full Drupal installation -- With/without JavaScript - -^ testing profile - ---- - -[.header: #3D85C6] - -## Functional tests - -- Slower to run -- Easiest to start with -- Provide most value - -^ Less setup steps No mocking etc. - ---- - -### _Exercise_ - -## Let's write a
functional test - ---- - -- Create a _web/modules/custom/workshop_ directory -- Create a `workshop.info.yml` file - ---- - -``` -# workshop.info.yml - -name: Drupal Testing Workshop -core: 8.x -type: module -``` - ---- - -- Create a _tests/src/Functional_ directory -- Create an _ExampleFunctionalTest.php_ file - ---- - -```php -// ExampleFunctionalTest.php - -namespace Drupal\Tests\workshop\Functional; - -use Drupal\Tests\BrowserTestBase; - -class ExampleFunctionalTest extends BrowserTestBase { - -} - -``` - ---- - -```php - -// ExampleFunctionalTest.php - -public function testExamplePageExists() { - -} -``` - ---- - -```php - -// ExampleFunctionalTest.php - -public function test_example_page_exists() { - -} -``` - -^ Snake case test method names Still works because it has the 'test' prefix More -readable than camel case? Works with Simpletest/D7 - ---- - -```php - -// ExampleFunctionalTest.php - -/** @test */ -public function example_page_exists() { - -} -``` - -^ Remove the prefix, use annotation PHPUnit only - ---- - -```php - -// ExampleFunctionalTest.php - -/** @test */ -public function example_page_exists() { - // Arrange - - // Act - - // Assert -} -``` - ---- - -```php - -// ExampleFunctionalTest.php - -/** @test */ -public function example_page_exists() { - // Given that I am an anonymous user. - - // When I go to /blog. - - // I should see the blog page. -} -``` - ---- - -```php -// ExampleFunctionalTest.php - -/** @test */ -public function example_page_exists() { - $this->drupalGet('/example-one'); - - $this->assertSession()->statusCodeEquals(200); -} -``` - ---- - -```php -// ExampleFunctionalTest.php - -protected static $modules = ['workshop']; -``` - ---- - -``` -PHPUnit 6.5.8 by Sebastian Bergmann and contributors. - -Testing Drupal\Tests\workshop\Functional\ExampleFunctionalTest - -Behat\Mink\Exception\ExpectationException : Current response status code is 404, but 200 expected. - /var/www/vendor/behat/mink/src/WebAssert.php:768 - /var/www/vendor/behat/mink/src/WebAssert.php:130 - /var/www/web/modules/custom/workshop/tests/src/Functional/ExampleFunctionalTest.php:14 - -Time: 18.2 seconds, Memory: 6.00MB - -ERRORS! -Tests: 1, Assertions: 2, Errors: 1. -``` - ---- - -- Create a _workshop.routing.yml_ file -- Create a Controller - ---- - -```yaml -# workshop.routing.yml - -workshop.example: - path: '/example-one' - defaults: - _controller: 'Drupal\workshop\Controller\ExampleController::index' - requirements: - _access: 'TRUE' -``` - ---- - -```php -// src/Controller/ExampleController.php - -namespace Drupal\workshop\Controller; - -class ExampleController { - - public function index() { - return []; - } - -} -``` - ---- - -``` -Time: 25.22 seconds, Memory: 6.00MB - -OK (1 test, 3 assertions) -``` - ---- - -[.header: #3D85C6] - -## Kernel tests - -- Integration tests -- Can install modules, interact with services, container, database -- Minimal Drupal bootstrap -- Faster than functional tests -- More setup required - ---- - -### _Exercise_ - -## Let's write a
kernel test - ---- - -- Create a _tests/src/Kernel_ directory -- Create an _ExampleKernelTest.php_ file -- Create a Service -- Use the service within the test to perform an action - ---- - -```php -// tests/src/Kernel/ExampleKernelTest.php - -namespace Drupal\Tests\workshop\Kernel; - -use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; -use Drupal\user\Entity\User; - -class ExampleKernelTest extends EntityKernelTestBase { - - public static $modules = ['workshop']; - -} - -``` - ---- - -```php -// tests/src/Kernel/ExampleKernelTest.php - -public function testUserDeleter { - $user = $this->createUser(); - - $user_deleter = \Drupal::service(UserDeleter::class); - $user_deleter->delete($user); - - $user = $this->reloadEntity($user); - - $this->assertNull($user); -} -``` - ---- - -```yaml -# workshop.services.yml - -services: - workshop.user_deleter: - class: Drupal\workshop\Service\UserDeleter -``` - ---- - -```yaml -# workshop.services.yml - -services: - Drupal\workshop\Service\UserDeleter: ~ -``` - ---- - -``` -Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException : -You have requested a non-existent service -"Drupal\Tests\workshop\Kernel\UserDeleter". -``` - ---- - -```php -// src/Service/UserDeleter.php - -namespace Drupal\workshop\Service; - -use Drupal\Core\Session\AccountInterface; - -class UserDeleter { - - public function delete(AccountInterface $user) { - user_delete($user->id()); - } - -} -``` - ---- - -```php -// tests/src/Kernel/ExampleKernelTest.php - -namespace Drupal\Tests\workshop\Kernel; - -use Drupal\workshop\Service\UserDeleter; -use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; -use Drupal\user\Entity\User; - -... -``` - -^ Import new UserDeleter - ---- - -``` -Drupal\Core\Entity\EntityStorageException : SQLSTATE[HY000]: -General error: 1 no such table: -test89378988.users_data: DELETE FROM {users_data} -WHERE uid IN (:db_condition_placeholder_0); Array -( - [:db_condition_placeholder_0] => 1 -) -``` - ---- - -```php -// tests/src/Kernel/ExampleKernelTest.php - -protected function setUp() { - parent::setUp(); - - $this->installSchema('user', ['users_data']); -} -``` - ---- - -``` -OK (1 test, 5 assertions) -``` - ---- - -[.header: #3D85C6] - -## Unit tests - -- Tests PHP logic -- No database interaction -- Fast to run -- Tightly coupled -- Mocking dependencies -- Hard to refactor - ---- - -### _Exercise_ - -## Let's write a
unit test - ---- - -```php -// tests/src/Unit/Service/ExampleUnitTest.php - -namespace Drupal\Tests\workshop\Unit; - -use Drupal\Tests\UnitTestCase; - -class ExampleUnitTest extends UnitTestCase { - - public function testAdd() { - $this->assertEquals(5, (new Calculator(3))->add(2)->calculate()); - } -} -``` - ---- - -``` -Error : Class 'Drupal\Tests\workshop\Unit\Calculator' not found - /var/www/web/modules/custom/workshop/tests/src/Unit/Service/ExampleUnitTest.php:10 -``` - ---- - -```php -// src/Service/Calculator.php - -namespace Drupal\workshop\Service; - -class Calculator { - - private $total; - - public function __construct($value) { - $this->total = $value; - } - - public function add($value) { - $this->total += $value; - - return $this; - } - - public function calculate() { - return $this->total; - } - -} -``` - ---- - -```php -// tests/src/Unit/Service/ExampleUnitTest.php - -namespace Drupal\Tests\workshop\Unit; - -use Drupal\workshop\Service\Calculator; -use Drupal\Tests\UnitTestCase; - -... -``` - ---- - -``` -Time: 4.55 seconds, Memory: 4.00MB - -OK (1 test, 1 assertion) -``` - ---- - -[.header: alignment(center)] - -## Test driven
development _(TDD)_ - ---- - -## _Test Driven Development_ - -- Write a failing test -- Write code until passes -- Refactor -- Repeat - ---- - -[.background-color: -#FFFFFF][.footer: https://github.com/foundersandcoders/testing-tdd-intro] -[.footer-style: #2F2F2F] - -![100%](../images/tdd-loop.png) - ---- - -## _How I Write Tests - "Outside In"_ - -- Start with functional tests -- Drop down to kernel or unit tests where needed -- Programming by wishful thinking -- Write comments first, then fill in the code -- Sometimes write assertions first - ---- - -### _Exercise_ - -## Let's build a blog using test driven development - ---- - -## _Acceptance criteria_ - -- As a site visitor -- I want to see a list of published articles at /blog -- Ordered by post date - ---- - -## _Tasks_ - -- Ensure the blog page exists -- Ensure only published articles are shown -- Ensure the articles are shown in the correct order - ---- - -## _Implementation_ - -- Use views module -- Do the mininum amount at each step, make no assumptions, let the tests guide - us -- Start with functional test - ---- - -### _Step 1_ - -## Create the module - ---- - -```yml -# tdd_blog.info.yml - -name: 'TDD Blog' -core: '8.x' -type: 'module' -``` - ---- - -### _Step 2_ - -## Ensure the blog page exists - ---- - -```php -// tests/src/Functional/BlogPageTest.php - -namespace Drupal\Tests\tdd_blog\Functional; - -use Drupal\Tests\BrowserTestBase; - -class BlogPageTest extends BrowserTestBase { - - protected static $modules = ['tdd_blog']; - -} -``` - ---- - -```php -public function testBlogPageExists() { - $this->drupalGet('/blog'); - - $this->assertSession()->statusCodeEquals(200); -} -``` - ---- - -``` -There was 1 error: - -1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists -Behat\Mink\Exception\ExpectationException: Current response status code is 404, but 200 expected. -``` - ---- - -- _The view has not been created_ -- Create a new view, page display -- Set the path -- Export the config -- Copy it into the module's `config/install` directory - ---- - -![fit](images/tdd-blog-1.png) - ---- - -![fit](images/tdd-blog-2.png) - ---- - -``` -drush cex -y - -cp ../config/default/views.view.blog.yml \ - modules/custom/tdd_blog/config/install -``` - ---- - -```diff -# views.view.blog.yml - -- uuid: 84305edf-7aef-4109-bc93-e87f685fb678 -langcode: en -status: true -dependencies: - config: - - node.type.article - module: - - node - - user -- _core: -- default_config_hash: iGZkqLWpwWNORq6_fy6v_Kn_KE4BjYHqj9vpgQsWJCs -id: blog -... -``` - ---- - -``` -1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists -Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided -by tdd_blog -have unmet dependencies: views.view.blog -(node.type.article, node, views) -``` - ---- - -```yml,[.highlight: 1, 7-10] -# tdd_blog.info.yml - -name: 'TDD Blog' -description: 'A demo module to show test driven module development.' -core: 8.x -type: module - -dependencies: - - 'drupal:node' - - 'drupal:views' -``` - ---- - -``` -1) Drupal\Tests\tdd_blog\Functional\BlogPageTest::testBlogPageExists -Drupal\Core\Config\UnmetDependenciesException: Configuration objects provided -by tdd_blog have unmet dependencies: -views.view.blog (node.type.article) -``` - ---- - -- Add the article content type - ---- - -``` -OK (1 test, 3 assertions) -``` - ---- - -[.build-lists: false] - -## _Tasks_ - -- ~~Ensure the blog page exists~~ -- Ensure only published articles are shown -- Ensure the articles are shown in the correct order - ---- - -### _Step 3_ - -## Ensure only published articles are shown - ---- - -```php -public function testOnlyPublishedArticlesAreShown() { - // Given I have a mixture of published and unpublished articles, - // as well as other types of content. - - // When I view the blog page. - - // I should only see the published articles. -} -``` - ---- - -### _Option 1_ - -## Functional tests - ---- - -```php -// modules/custom/tdd_blog/tests/src/Functional/BlogPageTest.php - -public function testOnlyPublishedArticlesAreShown() { - // Given I have a mixture of published and unpublished articles, - // as well as other types of content. - $node1 = $this->drupalCreateNode(['type' => 'page', 'status' => 1]); - $node2 = $this->drupalCreateNode(['type' => 'article', 'status' => 1]); - $node3 = $this->drupalCreateNode(['type' => 'article', 'status' => 0]); - - // When I view the blog page. - $this->drupalGet('/blog'); - - // I should only see the published articles. - $assert = $this->assertSession(); - $assert->pageTextContains($node2->label()); - $assert->pageTextNotContains($node1->label()); - $assert->pageTextNotContains($node3->label()); -} -``` - -^ Different ways to achieve this. This is taking the functional test approach. - ---- - -### _Option 2_ - -## Kernel tests - ---- - -```php -namespace Drupal\Tests\tdd_blog\Kernel; - -use Drupal\KernelTests\Core\Entity\EntityKernelTestBase; -use Drupal\Tests\node\Traits\NodeCreationTrait; - -class BlogPageTest extends EntityKernelTestBase { - - use NodeCreationTrait; - - public static $modules = ['node']; - -} -``` - ---- - -```php - -public function testOnlyPublishedArticlesAreShown() { - $this->createNode(['type' => 'page', 'status' => 1]); - $this->createNode(['type' => 'article', 'status' => 1]); - $this->createNode(['type' => 'article', 'status' => 0]); -} -``` - -^ Kernel test approach Dropping down a level No need for the brower, not -asserting against HTML Faster to run - ---- - -``` -1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testOnlyPublishedArticlesAreShown -Error: Call to a member function id() on boolean - -/var/www/web/core/modules/filter/filter.module:212 -/var/www/web/core/modules/node/tests/src/Traits/NodeCreationTrait.php:73 -/var/www/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:13 -``` - ---- - -```php -$this->installConfig(['filter']); -``` - ---- - -```php -public function testOnlyPublishedArticlesAreShown() { - ... - - $results = views_get_view_result('blog'); -} -``` - ---- - -```php -public function testOnlyPublishedArticlesAreShown() { - ... - - $results = views_get_view_result('blog'); - - $this->assertCount(1, $results); - $this->assertEquals(2, $results[0]->_entity->id()); -} -``` - ---- - -```php -public static $modules = [ - 'node', - 'tdd_blog', - 'views', -]; -``` - ---- - -```php -public function setUp() { - parent::setUp(); - - $this->installConfig(['filter', 'tdd_blog']); -} -``` - ---- - -``` -There was 1 failure: - -1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testOnlyPublishedArticlesAreShown -Failed asserting that actual size 2 matches expected size 1. - -/Users/opdavies/Code/drupal-testing-workshop/web/modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php:23 -``` - ---- - -![inline](images/tdd-blog-3.png) - ---- - -> - _There is no content type filter on the view_ - -- Add the filter -- Re-export and save the view - ---- - -![inline](images/tdd-blog-4.png) - ---- - -``` -OK (1 test, 6 assertions) -``` - ---- - -[.build-lists: false] - -## _Tasks_ - -- ~~Ensure the blog page exists~~ -- ~~Ensure only published articles are shown~~ -- Ensure the articles are shown in the correct order - ---- - -### _Step 4_ - -## Ensure the articles are ordered by date - ---- - -```php -// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php - -public function testArticlesAreOrderedByDate() { - // Given that I have numerous articles with different post dates. - - // When I go to the blog page. - - // The articles are ordered by post date. -} -``` - ---- - -```php -// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php - -public function testArticlesAreOrderedByDate() { - // Given that I have numerous articles with different post dates. - $this->createNode(['type' => 'article', 'created' => (new DrupalDateTime('+1 day'))->getTimestamp()]); - $this->createNode(['type' => 'article', 'created' => (new DrupalDateTime('+1 month'))->getTimestamp()]); - $this->createNode(['type' => 'article', 'created' => (new DrupalDateTime('+3 days'))->getTimestamp()]); - $this->createNode(['type' => 'article', 'created' => (new DrupalDateTime('+1 hour'))->getTimestamp()]); - - // When I go to the blog page. - - // The articles are ordered by post date. -} -``` - ---- - -```php -$this->createNode([ - 'type' => 'article', - 'created' => (new DrupalDateTime('+1 day'))->getTimestamp(), -]); -``` - -^ Array of default values - ---- - -```php -// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php - -public function testArticlesAreOrderedByDate() { - ... - - // When I go to the blog page. - $results = views_get_view_result('blog'); - - // The articles are ordered by post date. -} -``` - ---- - -```php -// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php - -public function testArticlesAreOrderedByDate() { - ... - - // When I go to the blog page. - $results = views_get_view_result('blog'); - - $nids = array_map(function(ResultRow $result) { - return $result->_entity->id(); - }, $results); - - // The articles are ordered by post date. -} -``` - ---- - -```php -// modules/custom/tdd_blog/tests/src/Kernel/BlogPageTest.php - -public function testArticlesAreOrderedByDate() { - ... - - // The articles are ordered by post date. - $this->assertEquals([4, 1, 3, 2], $nids); -} -``` - ---- - -``` -There was 1 failure: - -1) Drupal\Tests\tdd_blog\Kernel\BlogPageTest::testArticlesAreOrderedByDate -Failed asserting that two arrays are equal. ---- Expected -+++ Actual -@@ @@ - Array ( -- 0 => 4 -- 1 => 1 -- 2 => 3 -- 3 => 2 -+ 0 => '1' -+ 1 => '2' -+ 2 => '3' -+ 3 => '4' -``` - ---- - -![inline](images/tdd-blog-4.png) - ---- - -- _There is no sort order defined on the view_ -- Add the sort order -- Re-export the view - ---- - -![inline](images/tdd-blog-5.png) - ---- - -``` -OK (1 test, 5 assertions) -``` - ---- - -[.build-lists: false] - -## _Tasks_ - -- ~~Ensure the blog page exists~~ -- ~~Ensure only published articles are shown~~ -- ~~Ensure the articles are shown in the correct order~~ - ---- - -[.header: alignment(center)] - -## Take Aways - ---- - -- Testing has made me a _better developer_ -- Testing can produce _better quality code_ -- Use the _right type of test_ for the right situation -- Use the _right base class_, use available _traits_ -- Writing tests is an _investment_ -- OK to _start small_, introduce tests gradually -- Easier to _refactor_ -- Tests can pass, but things can _still be broken_. Tests only report on what - they cover. - -^ Made me think about how I'm going to do something more starting to do it Less -cruft, only write code that serves a purpose Spending time writing tests pays -dividends later on Start by introducing tests for new features or regression -tests when fixing bugs If you know things pass, then you can refactor code -knowing if something is broken Manual testing is still important - ---- - -[.header: alignment(center)] - -## Questions? - ---- - -[.header: alignment(center)] - -## Thanks diff --git a/src/having-fun-drupal-8-drupalorg-api/images/api-page.png b/src/having-fun-drupal-8-drupalorg-api/images/api-page.png deleted file mode 100644 index 8d365fe..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/api-page.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/api-result.png b/src/having-fun-drupal-8-drupalorg-api/images/api-result.png deleted file mode 100644 index 4c86ec6..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/api-result.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/do-projects-page.png b/src/having-fun-drupal-8-drupalorg-api/images/do-projects-page.png deleted file mode 100644 index 2cbf099..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/do-projects-page.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/do-projects-settings.png b/src/having-fun-drupal-8-drupalorg-api/images/do-projects-settings.png deleted file mode 100644 index 5aa779b..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/do-projects-settings.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/drupalversary.png b/src/having-fun-drupal-8-drupalorg-api/images/drupalversary.png deleted file mode 100644 index f5326d3..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/drupalversary.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/library-github.png b/src/having-fun-drupal-8-drupalorg-api/images/library-github.png deleted file mode 100644 index d015ab0..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/library-github.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/library-packagist.png b/src/having-fun-drupal-8-drupalorg-api/images/library-packagist.png deleted file mode 100644 index 8925d7b..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/library-packagist.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/library-travis.png b/src/having-fun-drupal-8-drupalorg-api/images/library-travis.png deleted file mode 100644 index f0f1049..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/library-travis.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/microserve-website.png b/src/having-fun-drupal-8-drupalorg-api/images/microserve-website.png deleted file mode 100644 index bda65b3..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/microserve-website.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/images/spatie-website.png b/src/having-fun-drupal-8-drupalorg-api/images/spatie-website.png deleted file mode 100644 index 150dbc7..0000000 Binary files a/src/having-fun-drupal-8-drupalorg-api/images/spatie-website.png and /dev/null differ diff --git a/src/having-fun-drupal-8-drupalorg-api/notes.md b/src/having-fun-drupal-8-drupalorg-api/notes.md deleted file mode 100644 index 8f219ef..0000000 --- a/src/having-fun-drupal-8-drupalorg-api/notes.md +++ /dev/null @@ -1,62 +0,0 @@ -# Having fun with Drupal 8, PHP libraries Drupal.org API - -- Open slides -- Open Chrome tabs -- Open PhpStorm for all projects -- Open Sequel Pro for both DBs - - Clear cache tables -- Start PHP server for each site -- Start recording - -## PHP library - -- Show in PhpStorm -- Show readme with examples - - Run test.php -- Show query classes - - Not drupal coding standards (PSR-2) - - Explain laravel collections -- Show entity classes -- Show tests - - Show fake query classes -- Run tests - -## Project statistics - -- Show /projects page -- Show routing -- Show ProjectController - - Using PHP 7 return types - - Explain dependency injection - - Explain about collection - - Explain render array - - Show how to change ordering -- Show ProjectRetriever - - More dependency injection - - Show services file -- Show settings form -- Add another module (Sophie's simple integrations?) - - See it loading on projects page - - See it cached - -## Drupalversary - -- Show front page -- Show block -- Show block form -- Show accountretriever - - Highlight caching - - Services file - - Show cached items in the DB -- Show routing -- Show UserController - - More dependency injection - - Services file -- Show date parser - - Show drupalversary model -- Show adding own username via form - - See it cached - - Show adding uid via form - - See it cached -- Show Dries' because this year drupalversary has passed -- Try with attendee ID diff --git a/src/having-fun-drupal-8-drupalorg-api/slides.txt b/src/having-fun-drupal-8-drupalorg-api/slides.txt deleted file mode 100644 index 495a570..0000000 --- a/src/having-fun-drupal-8-drupalorg-api/slides.txt +++ /dev/null @@ -1,210 +0,0 @@ -autoscale: true -build-lists: true -footer-style: alignment(left) -footer: @opdavies | opdavi.es -header-emphasis: #53B0EB -header: alignment(left) -text: alignment(left) -text-emphasis: #53B0EB -theme: poster, 8 - -[.header: alignment(center)] - -## Having fun with -## _Drupal 8_, _PHP libraries_ -## and the _Drupal.org API_ - ---- - -[.background-color: #FFFFFF] -[.build-lists: false] -[.header: #111111] -[.text: #111111, alignment(left)] - -![right 700%](../images/me-phpnw.png) - -- Full stack Web Developer & System Administrator -- Senior Developer at Microserve -- Part-time freelancer -- Acquia certified Drupal 8 Grand Master -- Drupal core contributor -- Open source project maintainer -- opdavies (Drupal.org, GitHub, Twitter) -- www.oliverdavies.uk - -^ Work at Microserve. -Maintain Drupal modules, PHP CLI tools and libraries -Talking about some open source project that I've written or in the process of writing. - ---- - -[.header: alignment(center)] - -## _Drupal 8 crash course_ - -### PHP libraries, Unit testing, -### Composer, Routing, Services, -### Dependency injection, caching - -^ Please feel free to ask questions as we go along! - ---- - -[.header: alignment(center)] - -## _Live Demo_ alert! - ---- - -[.hide-footer] - -![fit](images/microserve-website.png) - -^ In 2018 we rebuilt the Microserve website - ---- - -[.hide-footer] - -![fit](images/spatie-website.png) - -^ Looking for a way to replicate Spatie's open source page for Drupal - ---- - -### _Did you know that_ -## Drupal.org has an API? - -^ We're all familiar with Drupal.org (it's where everyone registered for this event), but did you know D.o has a public API? - ---- - -[.hide-footer] - -![fit](images/api-page.png) - ---- - -[.hide-footer] - -![fit](images/api-result.png) - ---- - -### _A PHP library for the_ -## Drupal.org API - -^ The first thing I built was... -It's what the Drupal examples are built on top of. - ---- - -- Retrieve _node_ and _user_ data -- Filter by properties -- Provides own entity classes -- Methods for retrieving common properties -- Reusable -- Unit tested - -^ Re-usable by Drupal 7, Drupal 8, Symfony, Laravel etc -Testing already covered. -Demo - ---- - -[.hide-footer] - -![fit](images/library-github.png) - ---- - -[.hide-footer] - -![fit](images/library-packagist.png) - ---- - -[.hide-footer] - -![fit](images/library-travis.png) - ---- - -```bash -$ composer require opdavies/drupalorg-api-php -``` - ---- - -### _Displaying Drupal.org_ -## project statistics - ---- - -[.text: alignment(left)] - -- Inspired by _spatie.be/en/opensource_ -- Displays _downloads_ and _stars_ -- Drupal 8 module - + Configuration form to enter project IDs - + Queries the API - + Displays project information - + Retrieved data cached locally - -^ Demo - ---- - -[.hide-footer] - -![fit](images/do-projects-settings.png) - ---- - -[.hide-footer] - -![fit](images/do-projects-page.png) - ---- - -### _When is your_ -## Drupalversary? - ---- - -[.text: alignment(left)] - -- When did you register on Drupal.org? -- Drupal 8 module - + Enter a username - + Queries the API - + Displays information - next Drupalversary _date_ and _number of days_ until, _number of years_ on Drupal.org - + Retrieved data cached locally - -^ Stored in cache tables, but could use a custom entity? -Demo - ---- - -[.hide-footer] - -![fit](images/drupalversary.png) - ---- - -- opdavi.es/_talks_ -- opdavi.es/_do-library_ -- opdavi.es/_drupalversary_ -- opdavi.es/_do-projects_ - ---- - -[.header: alignment(center)] - -## Questions? - ---- - -[.header: alignment(center)] - -# Thanks diff --git a/src/images/drupal-association-logo.png b/src/images/drupal-association-logo.png deleted file mode 100644 index 6c8b425..0000000 Binary files a/src/images/drupal-association-logo.png and /dev/null differ diff --git a/src/images/me-microserve.jpg b/src/images/me-microserve.jpg deleted file mode 100644 index 73c4e77..0000000 Binary files a/src/images/me-microserve.jpg and /dev/null differ diff --git a/src/images/me-phpnw-inviqa.jpg b/src/images/me-phpnw-inviqa.jpg deleted file mode 100644 index e87e6fc..0000000 Binary files a/src/images/me-phpnw-inviqa.jpg and /dev/null differ diff --git a/src/images/me-phpnw-inviqa.png b/src/images/me-phpnw-inviqa.png deleted file mode 100644 index dfd59af..0000000 Binary files a/src/images/me-phpnw-inviqa.png and /dev/null differ diff --git a/src/images/me-phpnw.png b/src/images/me-phpnw.png deleted file mode 100644 index dfd59af..0000000 Binary files a/src/images/me-phpnw.png and /dev/null differ diff --git a/src/images/me-precedent.jpg b/src/images/me-precedent.jpg deleted file mode 100644 index 4b3e031..0000000 Binary files a/src/images/me-precedent.jpg and /dev/null differ diff --git a/src/images/microserve-light.png b/src/images/microserve-light.png deleted file mode 100644 index 28c60a1..0000000 Binary files a/src/images/microserve-light.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/0.png b/src/taking-flight-with-tailwind-css/images/example/0.png deleted file mode 100644 index 5c18c18..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/0.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/1.png b/src/taking-flight-with-tailwind-css/images/example/1.png deleted file mode 100644 index 0933af5..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/1.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/10.png b/src/taking-flight-with-tailwind-css/images/example/10.png deleted file mode 100644 index 2a0bde4..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/10.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/11.png b/src/taking-flight-with-tailwind-css/images/example/11.png deleted file mode 100644 index 534f996..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/11.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/12.png b/src/taking-flight-with-tailwind-css/images/example/12.png deleted file mode 100644 index 85b310f..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/12.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/13.png b/src/taking-flight-with-tailwind-css/images/example/13.png deleted file mode 100644 index 9de9e18..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/13.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/14.png b/src/taking-flight-with-tailwind-css/images/example/14.png deleted file mode 100644 index af03c5c..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/14.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/2.png b/src/taking-flight-with-tailwind-css/images/example/2.png deleted file mode 100644 index cf0fe3f..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/2.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/3.png b/src/taking-flight-with-tailwind-css/images/example/3.png deleted file mode 100644 index 26233a4..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/3.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/4.png b/src/taking-flight-with-tailwind-css/images/example/4.png deleted file mode 100644 index ce168f4..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/4.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/5.png b/src/taking-flight-with-tailwind-css/images/example/5.png deleted file mode 100644 index 708d35c..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/5.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/6.png b/src/taking-flight-with-tailwind-css/images/example/6.png deleted file mode 100644 index 3199432..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/6.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/7.png b/src/taking-flight-with-tailwind-css/images/example/7.png deleted file mode 100644 index d74bc3c..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/7.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/8.png b/src/taking-flight-with-tailwind-css/images/example/8.png deleted file mode 100644 index 8c0db33..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/8.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/example/9.png b/src/taking-flight-with-tailwind-css/images/example/9.png deleted file mode 100644 index 7b52027..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/example/9.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/screenshot-laravel-nova.png b/src/taking-flight-with-tailwind-css/images/screenshot-laravel-nova.png deleted file mode 100644 index c5864e3..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/screenshot-laravel-nova.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/screenshot-rebuilding-bartik.png b/src/taking-flight-with-tailwind-css/images/screenshot-rebuilding-bartik.png deleted file mode 100644 index bea7ef3..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/screenshot-rebuilding-bartik.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/screenshot-send-firefox.png b/src/taking-flight-with-tailwind-css/images/screenshot-send-firefox.png deleted file mode 100644 index 9400658..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/screenshot-send-firefox.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/images/tailwind.svg b/src/taking-flight-with-tailwind-css/images/tailwind.svg deleted file mode 100644 index 920128d..0000000 --- a/src/taking-flight-with-tailwind-css/images/tailwind.svg +++ /dev/null @@ -1,10 +0,0 @@ - - Tailwind CSS - - - - - - - - diff --git a/src/taking-flight-with-tailwind-css/images/techs.png b/src/taking-flight-with-tailwind-css/images/techs.png deleted file mode 100644 index 525ab7a..0000000 Binary files a/src/taking-flight-with-tailwind-css/images/techs.png and /dev/null differ diff --git a/src/taking-flight-with-tailwind-css/taking-flight-tailwind-css.md b/src/taking-flight-with-tailwind-css/taking-flight-tailwind-css.md deleted file mode 100644 index b37ce8e..0000000 --- a/src/taking-flight-with-tailwind-css/taking-flight-tailwind-css.md +++ /dev/null @@ -1,920 +0,0 @@ -autoscale: true -theme: Plain Jane, 1 - -# **Taking Flight with
Tailwind CSS** - -![40%](images/tailwind.svg) - -^ Tailwind CSS is a framework that I've been using for the last year and a half -Going to be using Tailwind 1.0 which was released recently (May 13th) - ---- - -- PHP and Front End Developer -- System Administrator -- Senior Engineer at Inviqa -- Part-time freelancer -- Open sourcer -- @opdavies -- oliverdavies.uk - -![right](../images/me-phpnw.png) - -^ Co-organiser of PHP South Wales and DrupalCamp Bristol - ---- - -![125%](images/techs.png) - ---- - -# **What is Tailwind CSS?** - ---- - -[.footer: tailwindcss.com] - -# A **utility-first** CSS framework for rapidly building **custom designs**. - -^ CSS utility class generator PostCSS Make different looking sites using the -same class names No "Tailwind looking site" like there is with Bootstrap - ---- - -[.footer: tailwindcss.com] - -# Tailwind CSS is a **highly customizable**, **low-level** CSS framework - -^ No components like Bootstrap or Bulma Configure it per project Extendable if -needed via additional plugins Avoids the need to name things prematurely Can -extract components if needed (reusability) - ---- - -[.footer: tailwindcss.com/docs/what-is-tailwind/#designed-to-be-customized] - -# Tailwind is more than a CSS framework, it's an engine for
**creating design systems**. - -^ Good default values provided - colours, fonts, padding, widths Designing with -constraints. Using inline styles, every value is a magic number. With utilities, -you're choosing styles from a predefined design system, which makes it much -easier to build visually consistent UIs. - ---- - -- Text/border/background colours -- Font size/family/weight -- Alignment -- Padding/margin/negative margin -- Flexbox -- Positioning -- Lists -- z-index -- Opacity - -^ Some of the 'original' things that Tailwind would generate classes for. - ---- - -- Screenreader visibility -- Placeholder colour -- first-child, last-child, nth-child -- CSS Grid -- Transition -- Transform -- Spacing / Divide - -^ All generated from a single, customisable configuration file. - ---- - -![](images/screenshot-laravel-nova.png) - ---- - -![](images/screenshot-send-firefox.png) - ---- - -![](images/screenshot-rebuilding-bartik.png) - ---- - -# **How do I use Tailwind?** - -^ From the new tailwindcss.com website - ---- - -# With Tailwind, you style elements
by **applying pre-existing classes** directly in your HTML. - ---- - -# Using **utility classes** to build custom designs **without writing CSS** - ---- - -## **Benefits** - -- You aren't wasting time and energy inventing class names -- Your CSS stops growing -- Making changes feels safer - -^ No more adding silly class names like sidebar-inner-wrapper just to be able to -style something, and no more agonizing over the perfect abstract name for -something that's really just a flex container. - -^ Using a traditional approach, your CSS files get bigger every time you add a -new feature. With utilities, everything is reusable so you rarely need to write -new CSS. - -^ CSS is global and you never know what you're breaking when you make a change. -Classes in your HTML are local, so you can change them without worrying about -something else breaking. - ---- - -![500%](images/example/0.png) - ---- - -![500%](images/example/1.png) - -^ Add padding with p-6 - ---- - -![500%](images/example/2.png) - -^ Rounded image - rounded-full - ---- - -![500%](images/example/3.png) - -^ Centre image using mx-auto - ---- - -![500%](images/example/4.png) - -^ Larger text - text-lg - ---- - -![500%](images/example/5.png) - -^ Purple text - text-purple-500 - ---- - -![500%](images/example/6.png) - -^ Grey text - text-gray-600 - ---- - -![500%](images/example/7.png) - -^ Centre text - text-center - ---- - -![500%](images/example/8.png) - -^ Responsive: enable flexbox on medium screens - md:flex - ---- - -![500%](images/example/9.png) - -^ Remove margin around image - md:mx-0 - ---- - -![500%](images/example/10.png) - -^ Re-align text on medium screens - md:text-left - ---- - -![500%](images/example/11.png) - -^ md:mr-6 - add margin to the side of the image on medium screens - ---- - -![500%](images/example/12.png) - -^ Increase image size - md:h-24 md:w-24 - ---- - -![500%](images/example/13.png) - -^ Smaller view - ---- - -# **How do I install Tailwind?** - ---- - -# **1. Use the CDN** - ---- - -[.footer: https://next.tailwindcss.com/docs/installation] - -## **https://unpkg.com/tailwindcss/dist/tailwind.min.css** - ---- - -[.footer: https://next.tailwindcss.com/docs/installation] - -## **To get the most out of Tailwind,
you really should install it via npm.** - -^ - You can't customize Tailwind's default theme - -- You can't use any directives like _@apply_, _@variants_, etc. -- You can't enable features like _group-hover_ -- You can't install third-party plugins - ---- - -## **2. Installing Tailwind via NPM** - ---- - -## `npm install --save-dev`
`tailwindcss` - -## `yarn add -D tailwindcss` - -^ Adds it as a dependency to your package.json file - ---- - -## **Adding Tailwind to your CSS** - ---- - -[.code-highlight: 2-7] - -```css -/* src/css/app.pcss */ - -@tailwind base; - -@tailwind components; - -@tailwind utilities; -``` - ---- - -[.code-highlight: 5,9,13] - -``` -/* src/css/app.pcss */ - -@tailwind base; - -/* Custom base styles go here */ - -@tailwind components; - -/* Custom components go here */ - -@tailwind utilities; - -/* Custom utilities go here */ -``` - ---- - -## **Processing your CSS with Tailwind
with the build command** - -^ Compile the generated CSS Pass through PostCSS and Tailwind - ---- - -# `npx tailwind build`
`src/css/app.pcss`
`-o dist/css/app.css` - ---- - -```css -.text-left { - text-align: left; -} - -.text-center { - text-align: center; -} - -.text-right { - text-align: right; -} - -.text-justify { - text-align: justify; -} -``` - ---- - -## **Processing your CSS with Tailwind
with Laravel Mix** - ---- - -# `npm install --save-dev laravel-mix` - ---- - -```js -// webpack.mix.js - -const mix = require('laravel-mix') - -mix.postCss( - 'src/css/app.pcss', - 'dist/css', - [ - require('tailwindcss')() - ] -) -``` - -^ PostCSS - useful if you're including other PostCSS plugins like PostCSS Nested - ---- - -```js -// webpack.mix.js - -const mix = require('laravel-mix') - -require('laravel-mix-tailwind') - -mix.postCss('src/css/app.pcss', 'dist/css') - .tailwind() -``` - ---- - -```html - - - - - My new website - - - - -``` - ---- - -# `npm run dev` - -# `npm run watch` - -# `npm run prod` - ---- - -# **Interaction states** - -## hover, focus, active, disabled, visited,
group-hover, focus-within,
first-child, last-child... - -^ Start to differ from inline styles - ---- - -# `[state][separator][class]` - -^ State = hover, focus, group focus, focus within Separator = configurable, -colon by default Class = the same utility class that you would have used -normally - ---- - -# `hover:text-red-500` - ---- - -```css -.text-red-500 { - color: #f56565; -} - -.hover\:text-red-500:hover { - color: #f56565; -} - -.focus\:text-red-500:focus { - color: #f56565; -} -``` - ---- - -```html - - Read more - -``` - ---- - -```js -// defaultConfig.stub.js - -variants: { - alignContent: ['responsive'], - alignItems: ['responsive'], - alignSelf: ['responsive'], - appearance: ['responsive'], - backgroundAttachment: ['responsive'], - backgroundColor: ['responsive', 'hover', 'focus'], - backgroundPosition: ['responsive'], - backgroundRepeat: ['responsive'], - ... -``` - ---- - -# **Responsive** - -^ Mobile first - ---- - -# [fit] `.[screen][separator][class]` - ---- - -```js -// defaultConfig.stub.js - -screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', -}, -``` - ---- - -# `md:flex` - ---- - -# `md:hover:bg-red-500` - ---- - -```css -.block { - display: block; -} - -@media (min-width: 640px) { - .sm\:block { - display: block; - } -} - -@media (min-width: 768px) { - .md\:block { - display: block; - } -} -``` - ---- - -```html -
-
- Column 1 -
- -
- Column 2 -
-
-``` - ---- - -# **Keeping Things Small:
Controlling the File Size** - ---- - -# Disabling unused variants
and core plugins - ---- - -```js -// tailwind.config.js - -variants: { - alignContent: ['responsive'], - alignItems: ['responsive'], - alignSelf: ['responsive'], - appearance: ['responsive'], - backgroundAttachment: ['responsive'], - backgroundColor: ['responsive', 'hover', 'focus'], -``` - ---- - -```diff -// tailwind.config.js - -variants: { - alignContent: ['responsive'], - alignItems: ['responsive'], -- alignSelf: ['responsive'], -+ alignSelf: false, - appearance: ['responsive'], - backgroundAttachment: ['responsive'], -- backgroundColor: ['responsive', 'hover', 'focus'], -+ backgroundColor: ['responsive'], -``` - ---- - -# **Manually removing** unused or unwanted classes - ---- - -```js -screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', -}, -colors: { - transparent: 'transparent', - - black: '#000', - white: '#fff', - - gray: { - 100: '#f7fafc', - 200: '#edf2f7', - 300: '#e2e8f0', - 400: '#cbd5e0', - 500: '#a0aec0', - 600: '#718096', - 700: '#4a5568', - 800: '#2d3748', - 900: '#1a202c', - }, -``` - ---- - -```diff -screens: { - sm: '640px', - md: '768px', - lg: '1024px', -- xl: '1280px', -}, -colors: { - transparent: 'transparent', - - black: '#000', - white: '#fff', - - gray: { - 100: '#f7fafc', -- 200: '#edf2f7', - 300: '#e2e8f0', -- 400: '#cbd5e0', -- 500: '#a0aec0', - 600: '#718096', - 700: '#4a5568', -- 800: '#2d3748', - 900: '#1a202c', - }, -``` - -^ Needs to be done manually - ---- - -# **Automatically removing**
unused classes - ---- - -# `npm install --save-dev laravel-mix-purgecss` - ---- - -```js -const mix = require('laravel-mix') - -mix.postCss('src/css/site.css', 'dist/css').purgeCss({ - folders: ['templates'], - extensions: ['html', 'php', 'twig'], -}) -``` - ---- - -[.code-highlight: 1,3,6-9] - -```js -const mix = require('laravel-mix') - -require('laravel-mix-purgecss') - -mix.postCss('src/css/site.css', 'dist/css').purgeCss({ - folders: ['templates'], - extensions: ['html', 'php', 'twig'], -}) -``` - -^ Can be tricky using Drupal/WordPress as you don't know where the classes could -be coming from, no generated output directory - ---- - -# PurgeCSS is now **included by default** with Tailwind 1.4 - ---- - -[.code-highlight: 2-6] - - -```js -module.exports = { - purge: [ - './src/**/*.html', - './src/**/*.vue', - './src/**/*.jsx', - ], - theme: {}, - variants: {}, - plugins: [], -} -``` - ---- - -# Avoid repetition by **extracting components** - ---- - -# Does something **justify**
becoming a component? - ---- - -# Could the duplication
**be moved elsewhere**? - -^ Twig partials Vue components WordPress template parts - ---- - -```twig -{# base.html.twig #} - -{% for item in navItems %} - - {{ item.title }} - -{% endfor %} -``` - -^ Using a loop - ---- - -```twig -{# classes.html.twig #} - -

Adults

- -{% include 'class-list' with { - classes: page.classes, - type: 'adults', -} %} - -

Kids

- -{% include 'class-list' with { - classes: page.classes, - type: 'kids', -} %} -``` - -^ Move the duplicate markup into a partial, so there's only one version Pass -data in. - ---- - -```css -a.btn { - @apply text-sm no-underline font-bold; - @apply rounded-full inline-block px-5 py-2; - @apply text-white bg-blue-600; -} - -a.btn:hover { - @apply bg-blue-700; -} -``` - -^ Use utilities as mixins Copy classes from markup Still re-using the same -design system and constraints as before - ---- - -```css -a.btn { - font-size: 0.875rem; - text-decoration: none; - font-weight: 700; - border-radius: 9999px; - display: inline-block; - padding-left: 1.25rem; - padding-right: 1.25rem; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - color: #fff; - background-color: #3182ce; -} - -a.btn:hover { - background-color: #2b6cb0; -} -``` - ---- - -# **Customising Tailwind** - ---- - -# `npx tailwind init` - ---- - -```js -// tailwind.config.js - -module.exports = { - theme: { - extend: {}, - }, - plugins: [], - variants: {}, -} -``` - ---- - -[.code-highlight: 5-7] - -```js -// tailwind.config.js - -module.exports = { - theme: { - colors: { - inherit: 'inherit', - }, - extend: {}, - }, - plugins: [], - variants: {}, -} -``` - -^ Overrides all colours. - ---- - -[.code-highlight: 5-9] - -```js -// tailwind.config.js - -module.exports = { - theme: { - extend: { - colors: { - inherit: 'inherit', - }, - }, - }, - plugins: [], - variants: {}, -} -``` - -^ Extends Tailwind's default colours - ---- - -[.code-highlight: 1,4-5] - -```js -// tailwind.config.js - -module.exports = { - prefix: '', - important: false, - theme: { - extend: {}, - }, - plugins: [], - variants: {}, -} -``` - ---- - -# `npx tailwind init --full` - ---- - -# **Extending Tailwind CSS
with Plugins** - ---- - -# `npm install --save-dev tailwindcss-list-reset` - ---- - -[.code-highlight: 7-9] - -```js -// tailwind.config.js - -module.exports = { - theme: { - extend: {}, - }, - plugins: [require('tailwindcss-list-reset')()], - variants: {}, -} -``` - ---- - -```css -.list-reset { - list-style: none; - padding: 0; -} -``` - ---- - -```js -// index.js - -module.exports = variants => ({addUtilities}) => { - addUtilities( - { - '.list-reset': { - listStyle: 'none', - padding: 0, - }, - }, - variants, - ) -} -``` - ---- - -# **Demo** - ---- - -## **Useful links** - -- tailwindcss.com -- tailwindui.com -- builtwithtailwind.com -- youtube.com/adamwathan -- drupal.org/project/tailwindcss -- oliverdavies.uk/tags/tailwind-css -- oliverdavies.uk/tailwind-repos - ---- - -# **Questions?** - -### oliverdavies.uk/tailwind-talk
@opdavies diff --git a/src/test-driven-drupal/images/2c6qi8.jpg b/src/test-driven-drupal/images/2c6qi8.jpg deleted file mode 100644 index 93bd9a9..0000000 Binary files a/src/test-driven-drupal/images/2c6qi8.jpg and /dev/null differ diff --git a/src/test-driven-drupal/images/afilina-tweet.png b/src/test-driven-drupal/images/afilina-tweet.png deleted file mode 100644 index 4cb59c1..0000000 Binary files a/src/test-driven-drupal/images/afilina-tweet.png and /dev/null differ diff --git a/src/test-driven-drupal/images/appnovation.png b/src/test-driven-drupal/images/appnovation.png deleted file mode 100644 index 49e432c..0000000 Binary files a/src/test-driven-drupal/images/appnovation.png and /dev/null differ diff --git a/src/test-driven-drupal/images/broadbean-drupal-flow-1.png b/src/test-driven-drupal/images/broadbean-drupal-flow-1.png deleted file mode 100644 index 860c6c3..0000000 Binary files a/src/test-driven-drupal/images/broadbean-drupal-flow-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/broadbean-drupal-flow-2.png b/src/test-driven-drupal/images/broadbean-drupal-flow-2.png deleted file mode 100644 index da80f78..0000000 Binary files a/src/test-driven-drupal/images/broadbean-drupal-flow-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/broadbean-website.png b/src/test-driven-drupal/images/broadbean-website.png deleted file mode 100644 index 37d7bf1..0000000 Binary files a/src/test-driven-drupal/images/broadbean-website.png and /dev/null differ diff --git a/src/test-driven-drupal/images/broadbean.png b/src/test-driven-drupal/images/broadbean.png deleted file mode 100644 index 3aaf673..0000000 Binary files a/src/test-driven-drupal/images/broadbean.png and /dev/null differ diff --git a/src/test-driven-drupal/images/collection-class-1.png b/src/test-driven-drupal/images/collection-class-1.png deleted file mode 100644 index 3c1d004..0000000 Binary files a/src/test-driven-drupal/images/collection-class-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/collection-class-2.png b/src/test-driven-drupal/images/collection-class-2.png deleted file mode 100644 index 09be34e..0000000 Binary files a/src/test-driven-drupal/images/collection-class-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-1.png b/src/test-driven-drupal/images/d8-simpletest-1.png deleted file mode 100644 index 5ef734a..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-2.png b/src/test-driven-drupal/images/d8-simpletest-2.png deleted file mode 100644 index 6a86356..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-3.png b/src/test-driven-drupal/images/d8-simpletest-3.png deleted file mode 100644 index 9f2e423..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-3.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-4.png b/src/test-driven-drupal/images/d8-simpletest-4.png deleted file mode 100644 index 162c867..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-4.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-5.png b/src/test-driven-drupal/images/d8-simpletest-5.png deleted file mode 100644 index 2e1e4fe..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-5.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-6.png b/src/test-driven-drupal/images/d8-simpletest-6.png deleted file mode 100644 index 33e29f6..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-6.png and /dev/null differ diff --git a/src/test-driven-drupal/images/d8-simpletest-7.png b/src/test-driven-drupal/images/d8-simpletest-7.png deleted file mode 100644 index 9b5463d..0000000 Binary files a/src/test-driven-drupal/images/d8-simpletest-7.png and /dev/null differ diff --git a/src/test-driven-drupal/images/dcbristol.png b/src/test-driven-drupal/images/dcbristol.png deleted file mode 100644 index 552904f..0000000 Binary files a/src/test-driven-drupal/images/dcbristol.png and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-1.jpeg b/src/test-driven-drupal/images/ddd-1.jpeg deleted file mode 100644 index 6f49fc8..0000000 Binary files a/src/test-driven-drupal/images/ddd-1.jpeg and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-2.jpeg b/src/test-driven-drupal/images/ddd-2.jpeg deleted file mode 100644 index 9f5261d..0000000 Binary files a/src/test-driven-drupal/images/ddd-2.jpeg and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-3.jpeg b/src/test-driven-drupal/images/ddd-3.jpeg deleted file mode 100644 index a09ca7d..0000000 Binary files a/src/test-driven-drupal/images/ddd-3.jpeg and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-4.jpeg b/src/test-driven-drupal/images/ddd-4.jpeg deleted file mode 100644 index bbfce47..0000000 Binary files a/src/test-driven-drupal/images/ddd-4.jpeg and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-5.jpg b/src/test-driven-drupal/images/ddd-5.jpg deleted file mode 100644 index 7d575a3..0000000 Binary files a/src/test-driven-drupal/images/ddd-5.jpg and /dev/null differ diff --git a/src/test-driven-drupal/images/ddd-5.png b/src/test-driven-drupal/images/ddd-5.png deleted file mode 100644 index a75093a..0000000 Binary files a/src/test-driven-drupal/images/ddd-5.png and /dev/null differ diff --git a/src/test-driven-drupal/images/deploy-all-the-things.jpg b/src/test-driven-drupal/images/deploy-all-the-things.jpg deleted file mode 100644 index f90028e..0000000 Binary files a/src/test-driven-drupal/images/deploy-all-the-things.jpg and /dev/null differ diff --git a/src/test-driven-drupal/images/files.png b/src/test-driven-drupal/images/files.png deleted file mode 100644 index a23b62a..0000000 Binary files a/src/test-driven-drupal/images/files.png and /dev/null differ diff --git a/src/test-driven-drupal/images/homer-smart.png b/src/test-driven-drupal/images/homer-smart.png deleted file mode 100644 index 50c5705..0000000 Binary files a/src/test-driven-drupal/images/homer-smart.png and /dev/null differ diff --git a/src/test-driven-drupal/images/kernel-tests.png b/src/test-driven-drupal/images/kernel-tests.png deleted file mode 100644 index 20921a7..0000000 Binary files a/src/test-driven-drupal/images/kernel-tests.png and /dev/null differ diff --git a/src/test-driven-drupal/images/matt-stauffer-tweet.png b/src/test-driven-drupal/images/matt-stauffer-tweet.png deleted file mode 100644 index 3f27a45..0000000 Binary files a/src/test-driven-drupal/images/matt-stauffer-tweet.png and /dev/null differ diff --git a/src/test-driven-drupal/images/me.jpg b/src/test-driven-drupal/images/me.jpg deleted file mode 100644 index 4b3e031..0000000 Binary files a/src/test-driven-drupal/images/me.jpg and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2012-1.png b/src/test-driven-drupal/images/override-node-options-2012-1.png deleted file mode 100644 index 4e44b42..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2012-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2012-2.png b/src/test-driven-drupal/images/override-node-options-2012-2.png deleted file mode 100644 index 0c2d53b..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2012-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2012-3.png b/src/test-driven-drupal/images/override-node-options-2012-3.png deleted file mode 100644 index 700cb86..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2012-3.png and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2012-4.png b/src/test-driven-drupal/images/override-node-options-2012-4.png deleted file mode 100644 index ac53a5d..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2012-4.png and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2020-1.png b/src/test-driven-drupal/images/override-node-options-2020-1.png deleted file mode 100644 index aff4836..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2020-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/override-node-options-2020-2.png b/src/test-driven-drupal/images/override-node-options-2020-2.png deleted file mode 100644 index c6000d8..0000000 Binary files a/src/test-driven-drupal/images/override-node-options-2020-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/phpstorm-integration.png b/src/test-driven-drupal/images/phpstorm-integration.png deleted file mode 100644 index c0d12c7..0000000 Binary files a/src/test-driven-drupal/images/phpstorm-integration.png and /dev/null differ diff --git a/src/test-driven-drupal/images/phpunit.png b/src/test-driven-drupal/images/phpunit.png deleted file mode 100644 index d22c405..0000000 Binary files a/src/test-driven-drupal/images/phpunit.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest-1.png b/src/test-driven-drupal/images/simpletest-1.png deleted file mode 100644 index 368de76..0000000 Binary files a/src/test-driven-drupal/images/simpletest-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest-2.png b/src/test-driven-drupal/images/simpletest-2.png deleted file mode 100644 index f823167..0000000 Binary files a/src/test-driven-drupal/images/simpletest-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest-3.png b/src/test-driven-drupal/images/simpletest-3.png deleted file mode 100644 index c413758..0000000 Binary files a/src/test-driven-drupal/images/simpletest-3.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest-4.png b/src/test-driven-drupal/images/simpletest-4.png deleted file mode 100644 index fcce824..0000000 Binary files a/src/test-driven-drupal/images/simpletest-4.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest-countdown.png b/src/test-driven-drupal/images/simpletest-countdown.png deleted file mode 100644 index 7508188..0000000 Binary files a/src/test-driven-drupal/images/simpletest-countdown.png and /dev/null differ diff --git a/src/test-driven-drupal/images/simpletest.png b/src/test-driven-drupal/images/simpletest.png deleted file mode 100644 index 76c497c..0000000 Binary files a/src/test-driven-drupal/images/simpletest.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tada.png b/src/test-driven-drupal/images/tada.png deleted file mode 100644 index 4978ad7..0000000 Binary files a/src/test-driven-drupal/images/tada.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tawny-tweet-1.png b/src/test-driven-drupal/images/tawny-tweet-1.png deleted file mode 100644 index bf954fa..0000000 Binary files a/src/test-driven-drupal/images/tawny-tweet-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tawny-tweet-2.png b/src/test-driven-drupal/images/tawny-tweet-2.png deleted file mode 100644 index ea425d4..0000000 Binary files a/src/test-driven-drupal/images/tawny-tweet-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-1.png b/src/test-driven-drupal/images/tdd-blog-1.png deleted file mode 100644 index ea4fdc0..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-2.png b/src/test-driven-drupal/images/tdd-blog-2.png deleted file mode 100644 index 3bce812..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-3.png b/src/test-driven-drupal/images/tdd-blog-3.png deleted file mode 100644 index 3b20e02..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-3.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-4.png b/src/test-driven-drupal/images/tdd-blog-4.png deleted file mode 100644 index 66a0b80..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-4.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-5.png b/src/test-driven-drupal/images/tdd-blog-5.png deleted file mode 100644 index b50dd8a..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-5.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-directories.png b/src/test-driven-drupal/images/tdd-blog-directories.png deleted file mode 100644 index 17eb9fa..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-directories.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-blog-installed.png b/src/test-driven-drupal/images/tdd-blog-installed.png deleted file mode 100644 index e40926b..0000000 Binary files a/src/test-driven-drupal/images/tdd-blog-installed.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-circle-of-life.png b/src/test-driven-drupal/images/tdd-circle-of-life.png deleted file mode 100644 index 78e5f34..0000000 Binary files a/src/test-driven-drupal/images/tdd-circle-of-life.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-drupal-tasks.png b/src/test-driven-drupal/images/tdd-drupal-tasks.png deleted file mode 100644 index 35376c3..0000000 Binary files a/src/test-driven-drupal/images/tdd-drupal-tasks.png and /dev/null differ diff --git a/src/test-driven-drupal/images/tdd-loop.png b/src/test-driven-drupal/images/tdd-loop.png deleted file mode 100644 index ffd6078..0000000 Binary files a/src/test-driven-drupal/images/tdd-loop.png and /dev/null differ diff --git a/src/test-driven-drupal/images/timmillwood-ono.png b/src/test-driven-drupal/images/timmillwood-ono.png deleted file mode 100644 index be4eda4..0000000 Binary files a/src/test-driven-drupal/images/timmillwood-ono.png and /dev/null differ diff --git a/src/test-driven-drupal/images/title.png b/src/test-driven-drupal/images/title.png deleted file mode 100644 index 3110bf9..0000000 Binary files a/src/test-driven-drupal/images/title.png and /dev/null differ diff --git a/src/test-driven-drupal/images/toggle-optional-fields-1.png b/src/test-driven-drupal/images/toggle-optional-fields-1.png deleted file mode 100644 index 8378788..0000000 Binary files a/src/test-driven-drupal/images/toggle-optional-fields-1.png and /dev/null differ diff --git a/src/test-driven-drupal/images/toggle-optional-fields-2.png b/src/test-driven-drupal/images/toggle-optional-fields-2.png deleted file mode 100644 index 4112014..0000000 Binary files a/src/test-driven-drupal/images/toggle-optional-fields-2.png and /dev/null differ diff --git a/src/test-driven-drupal/images/toggle-optional-fields-3.png b/src/test-driven-drupal/images/toggle-optional-fields-3.png deleted file mode 100644 index 8339887..0000000 Binary files a/src/test-driven-drupal/images/toggle-optional-fields-3.png and /dev/null differ diff --git a/src/test-driven-drupal/images/toggle-optional-fields-button.png b/src/test-driven-drupal/images/toggle-optional-fields-button.png deleted file mode 100644 index 7f8db5f..0000000 Binary files a/src/test-driven-drupal/images/toggle-optional-fields-button.png and /dev/null differ diff --git a/src/test-driven-drupal/images/when-you-do-things-right.jpg b/src/test-driven-drupal/images/when-you-do-things-right.jpg deleted file mode 100644 index efe0ac4..0000000 Binary files a/src/test-driven-drupal/images/when-you-do-things-right.jpg and /dev/null differ diff --git a/src/test-driven-drupal/slides.md b/src/test-driven-drupal/slides.md deleted file mode 100644 index aae6c50..0000000 --- a/src/test-driven-drupal/slides.md +++ /dev/null @@ -1,961 +0,0 @@ -theme: Simple, 8 -autoscale: true -build-lists: true -header: alignment(left), line-height(1.1), text-scale(1.3) -text: alignment(left) -text-emphasis: #53B0EB - - -![](images/title.png) - -[.header: alignment(center)] - -# **TDD: Test
Driven Drupal** - ---- - -- Why write tests, and what to test -- Types of tests -- How to run tests -- Example -- Building a new module with test driven development - ---- - -[.background-color: #FFFFFF] -[.build-lists: false] -[.header: #111111] -[.text: #111111, alignment(left)] - -![right 800%](../images/me-phpnw.png) - -- Full Stack Web Developer & System Administrator -- Senior Software Engineer at Inviqa -- PHP South Wales organiser -- @opdavies -- www.oliverdavies.uk - -^ - Work at Inviqa. -- Organiser of the PHP South Wales user group. Formerly PHP South West, Drupal Bristol, SWDUG -- Maintain Drupal modules, PHP CLI tools and libraries -- Blog on my website - ---- - -[.header: alignment(center)] - -## Write **custom modules
and themes** for clients - ---- - -[.header: alignment(center)] - -## Contributor to **Drupal core** - -^ - Drupal 7 and 8 core contributor -- Most recent patch submitted on a live stream - ---- - -[.header: alignment(center)] - -## Maintain and contribute
to **contrib projects** - -^ Approaching this from a few different angles - ---- - -[.background-color: #FFFFFF] - -![inline 150%](images/timmillwood-ono.png) - ---- - -## Override Node Options - -- Become maintainer in 2012 -- **#232** most used module on Drupal.org (May 2020) -- Had some existing tests -- Crucial to preventing regressions - -^ Preventing regressions when adding new features or fixing bugs, but also user -submitted patches First module I ported to Drupal 8, aided by tests - ---- - -![](images/override-node-options-2012-1.png) - ---- - -![](images/override-node-options-2012-4.png) - ---- - -![](images/override-node-options-2020-2.png) - -^ - D5 and D6 gone down, D7 up and a few different D8 versions including D9 compatibility. -- Around 30,000 sites - ---- - -[.header: alignment(center)] - -## **Why write tests?** - ---- - -## Why write tests? - -- Catch bugs earlier -- Peace of mind -- Prevent regressions -- Write less code -- Documentation -- Drupal core requirement -- More important with regular D8/D9 releases and supporting multiple versions - -^ Dave Liddament talk - better and cheaper to catch bugs earlier (e.g. whilst developing rather than after it's been released) -Refer to tests when writing implementation code ONO merge conflict - ---- - -## Core Testing Gate - -| Description | When | -| --- | --- | -| Check test coverage and ensure all tests pass | When changing/refactoring existing code | -| Add new tests | When adding new features | -| Upload a test case that fails | When fixing bugs in PHP code | -| Add JavaScript test | When making JS changes | -| Manually test in browsers and provide screenshots or screencasts | When making markup or CSS changes | -| Provide an example module | When a new feature is not implemented by Drupal core | - -[.footer: https://opdavi.es/drupal-core-testing-gate] - ---- - -## Testing in Drupal - -- **Drupal 7** - SimpleTest (testing) module provided as part of core -- **Drupal 8** - PHPUnit added as a core dependency, later became the default via the PHPUnit initiative -- **Drupal 9** - SimpleTest removed, moved to contrib - ---- - -## Writing Tests (Drupal 8) - -- PHP class with **.php** extension -- **tests/src** directory within each module -- Within the **Drupal\Tests\module_name** namespace -- Class name must match the filename -- Namespace must match the directory structure -- One test class per feature - -^ Different to D7 - ---- - -[.header: alignment(center)] - -## **Arrange** - -## **Act** - -## **Assert** - ---- - -[.header: alignment(center)] - -## **Given** - -## **When** - -## **Then** - ---- - -[.header: alignment(center)] - -## **Given** the About page exists - -## **When** I go to the page - -## **Then** I should see "About Me" - ---- - -```php, [.highlight: 1-3] -// modules/example/tests/src/Functional/ExampleTest.php - -namespace Drupal\Tests\example\Functional; - -use Drupal\Tests\BrowserTestBase; - -class ExampleTest extends BrowserTestBase { - - public function testSomething() { - // Given... - // When... - // Then... - } - -} -``` - ---- - -```php, [.highlight: 5-7] -// modules/example/tests/src/Functional/ExampleTest.php - -namespace Drupal\Tests\example\Functional; - -use Drupal\Tests\BrowserTestBase; - -class ExampleTest extends BrowserTestBase { - - public function testSomething() { - // Given... - // When... - // Then... - } - -} -``` - ---- - -```php, [.highlight: 9,13] -// modules/example/tests/src/Functional/ExampleTest.php - -namespace Drupal\Tests\example\Functional; - -use Drupal\Tests\BrowserTestBase; - -class ExampleTest extends BrowserTestBase { - - public function testSomething() { - // Given... - // When... - // Then... - } - -} -``` - ---- - -```php, [.highlight: 10-12] -// modules/example/tests/src/Functional/ExampleTest.php - -namespace Drupal\Tests\example\Functional; - -use Drupal\Tests\BrowserTestBase; - -class ExampleTest extends BrowserTestBase { - - public function testSomething() { - // Given... - // When... - // Then... - } - -} -``` - ---- - -```php -public function testSomething() {} - -public function test_something() {} - -/** @test */ -public function it_does_something() {} -``` - ---- - -## What to test? - -- Creating nodes with data from an API -- Calculating attendance figures for an event -- Determining if an event is purchasble -- Promotions and coupons for new users -- Cloning events -- Queuing private message requests -- Emails for new memberships -- Closed support tickets are re-opened when comments are added -- Custom form validation rules - -^ Examples of some things that I tested on a previous project. - ---- - -[.background-color: #FFFFFF] - -![inline 125%](images/matt-stauffer-tweet.png) - ---- - -[.header: alignment(center) ] - -## **Types of Tests** - ---- - -## Types of Tests - -- **Functional** / **FunctionalJavascript** (web, browser, feature) -- **Kernel** (integration) -- **Unit** - ---- - -## Functional Tests - -- Tests end-to-end functionality -- UI testing -- Interacts with database -- Full Drupal installation -- Slower to run -- With/without JavaScript - -^ testing profile Functional/FunctionalJavascript Nightwatch - ---- - -```php -class BlockTest extends BlockTestBase { - - public function testBlockVisibility() { - $block_name = 'system_powered_by_block'; - $title = $this->randomMachineName(8); - - $default_theme = $this->config('system.theme')->get('default'); - - $edit = [ - 'id' => strtolower($this->randomMachineName(8)), - 'region' => 'sidebar_first', - 'settings[label]' => $title, - 'settings[label_display]' => TRUE, - ]; - - $edit['visibility[request_path][pages]'] = '/user*'; - $edit['visibility[request_path][negate]'] = TRUE; - $edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE; - - // ... - } -``` - ---- - -```php, [.highlight: 4-18] -class BlockTest extends BlockTestBase { - - public function testBlockVisibility() { - $block_name = 'system_powered_by_block'; - $title = $this->randomMachineName(8); - - $default_theme = $this->config('system.theme')->get('default'); - - $edit = [ - 'id' => strtolower($this->randomMachineName(8)), - 'region' => 'sidebar_first', - 'settings[label]' => $title, - 'settings[label_display]' => TRUE, - ]; - - $edit['visibility[request_path][pages]'] = '/user*'; - $edit['visibility[request_path][negate]'] = TRUE; - $edit['visibility[user_role][roles][' . RoleInterface::AUTHENTICATED_ID . ']'] = TRUE; - - // ... - } -``` - -^ Arrange step - ---- - -```php - -class BlockTest extends BlockTestBase { - - public function testBlockVisibility() { - // ... - - $this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme); - $this->assertFieldChecked('edit-visibility-request-path-negate-0'); - - $this->drupalPostForm(NULL, $edit, t('Save block')); - $this->assertText('The block configuration has been saved.', 'Block was saved'); - - $this->clickLink('Configure'); - $this->assertFieldChecked('edit-visibility-request-path-negate-1'); - - $this->drupalGet(''); - $this->assertText($title, 'Block was displayed on the front page.'); - - $this->drupalGet('user'); - $this->assertNoText($title, 'Block was not displayed according to block visibility rules.'); - - // ... - } -``` - ---- - -```php, [.highlight: 6,9,12,15,18] -class BlockTest extends BlockTestBase { - - public function testBlockVisibility() { - // ... - - $this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme); - $this->assertFieldChecked('edit-visibility-request-path-negate-0'); - - $this->drupalPostForm(NULL, $edit, t('Save block')); - $this->assertText('The block configuration has been saved.', 'Block was saved'); - - $this->clickLink('Configure'); - $this->assertFieldChecked('edit-visibility-request-path-negate-1'); - - $this->drupalGet(''); - $this->assertText($title, 'Block was displayed on the front page.'); - - $this->drupalGet('user'); - $this->assertNoText($title, 'Block was not displayed according to block visibility rules.'); - - // ... - } -``` - ---- - -```php, [.highlight: 7,10,13,16,19] -class BlockTest extends BlockTestBase { - - public function testBlockVisibility() { - // ... - - $this->drupalGet('admin/structure/block/add/' . $block_name . '/' . $default_theme); - $this->assertFieldChecked('edit-visibility-request-path-negate-0'); - - $this->drupalPostForm(NULL, $edit, t('Save block')); - $this->assertText('The block configuration has been saved.', 'Block was saved'); - - $this->clickLink('Configure'); - $this->assertFieldChecked('edit-visibility-request-path-negate-1'); - - $this->drupalGet(''); - $this->assertText($title, 'Block was displayed on the front page.'); - - $this->drupalGet('user'); - $this->assertNoText($title, 'Block was not displayed according to block visibility rules.'); - - // ... - } -``` - ---- - -## Kernel Tests - -- Integration tests -- Can install modules, interact with services, container, database -- Minimal Drupal bootstrap -- Faster than functional tests -- More setup required - ---- - -```php - -class BlockRebuildTest extends KernelTestBase { - - use BlockCreationTrait; - - public static $modules = ['block', 'system']; - - protected function setUp() { - parent::setUp(); - - $this->container->get('theme_installer') - ->install(['stable', 'classy']); - - $this->container->get('config.factory') - ->getEditable('system.theme') - ->set('default', 'classy') - ->save(); - } - - // ... - -} -``` - ---- - -```php, [.highlight: 5, 10-16] - -class BlockRebuildTest extends KernelTestBase { - - use BlockCreationTrait; - - public static $modules = ['block', 'system']; - - protected function setUp() { - parent::setUp(); - - $this->container->get('theme_installer') - ->install(['stable', 'classy']); - - $this->container->get('config.factory') - ->getEditable('system.theme') - ->set('default', 'classy') - ->save(); - } - - // ... - -} -``` - -^ Still have access to the service container, via $this->container - ---- - -```php -class BlockRebuildTest extends KernelTestBase { - - // ... - - public function testRebuildNoBlocks() { - block_rebuild(); - - $messages = \Drupal::messenger()->all(); - \Drupal::messenger()->deleteAll(); - - $this->assertEquals([], $messages); - } - -} -``` - -^ Can still access services like \Drupal::messenger() - ---- - -## Unit Tests - -- Tests PHP logic -- No database interaction -- Fast to run -- Need to mock dependencies -- Can become tightly coupled -- Can be hard to refactor - ---- - -```php -class BlockRepositoryTest extends UnitTestCase { - - public function testGetVisibleBlocksPerRegion(array $blocks_config, array $expected_blocks) { - $blocks = []; - - foreach ($blocks_config as $block_id => $block_config) { - $block = $this->getMock('Drupal\block\BlockInterface'); - - $block->expects($this->once()) - ->method('access') - ->will($this->returnValue($block_config[0])); - - $block->expects($block_config[0] ? $this->atLeastOnce() : $this->never()) - ->method('getRegion') - ->willReturn($block_config[1]); - - $block->expects($this->any()) - ->method('label') - ->willReturn($block_id); - - // ... - - $blocks[$block_id] = $block; - } - - // ... - } -} -``` - ---- - -```php, [.highlight: 7-20] - -class BlockRepositoryTest extends UnitTestCase { - - public function testGetVisibleBlocksPerRegion(array $blocks_config, array $expected_blocks) { - $blocks = []; - - foreach ($blocks_config as $block_id => $block_config) { - $block = $this->getMock('Drupal\block\BlockInterface'); - - $block->expects($this->once()) - ->method('access') - ->will($this->returnValue($block_config[0])); - - $block->expects($block_config[0] ? $this->atLeastOnce() : $this->never()) - ->method('getRegion') - ->willReturn($block_config[1]); - - $block->expects($this->any()) - ->method('label') - ->willReturn($block_id); - - // ... - - $blocks[$block_id] = $block; - } - - // ... - } -} -``` - ---- - -```php -class BlockRepositoryTest extends UnitTestCase { - - public function testGetVisibleBlocksPerRegion(array $blocks_config, array $expected_blocks) { - // .. - - $this->blockStorage->expects($this->once()) - ->method('loadByProperties') - ->with(['theme' => $this->theme]) - ->willReturn($blocks); - - $result = []; - $cacheable_metadata = []; - - foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) { - $result[$region] = []; - - foreach ($resulting_blocks as $plugin_id => $block) { - $result[$region][] = $plugin_id; - } - } - - $this->assertEquals($expected_blocks, $result); - } - -} -``` - ---- - -```php, [.highlight: 14-22] -class BlockRepositoryTest extends UnitTestCase { - - public function testGetVisibleBlocksPerRegion(array $blocks_config, array $expected_blocks) { - // .. - - $this->blockStorage->expects($this->once()) - ->method('loadByProperties') - ->with(['theme' => $this->theme]) - ->willReturn($blocks); - - $result = []; - $cacheable_metadata = []; - - foreach ($this->blockRepository->getVisibleBlocksPerRegion($cacheable_metadata) as $region => $resulting_blocks) { - $result[$region] = []; - - foreach ($resulting_blocks as $plugin_id => $block) { - $result[$region][] = $plugin_id; - } - } - - $this->assertEquals($expected_blocks, $result); - } - -} -``` - ---- - -[.header: alignment(center)] - -# **Example** - ---- - -![](images/broadbean-website.png) - ---- - -## Specification - -- Job adverts created in Broadbean UI, needs to create nodes in Drupal -- Application URL links users to separate application system -- Jobs need to be linked to offices -- Job length specified in number of days -- Path is specified as a field in the API -- Application URL constructed from domain, includes role ID as a GET parameter and optionally UTM parameters - ---- - -[.background-color: #FFFFFF] - -![inline 125%](images/broadbean-drupal-flow-2.png) - ---- - -## Implementation - -- Added route to accept data from API as XML -- Added system user with API role to authenticate -- **active_for** converted from number of days to UNIX timestamp -- **branch_name** and **locations** converted from plain text to entity reference (job node to office node) -- **url_alias** property mapped to **path** - ---- - -```php -$data = [ - 'command' => 'add', - 'username' => 'bobsmith', - 'password' => 'p455w0rd', - 'active_for' => '365', - 'application_email' => 'bob.12345.123@smith.aplitrak.com', - 'branch_address' => '123 Fake St, Bristol, BS1 2AB', - 'branch_name' => 'Test', - 'contract' => 'Temporary', - 'details' => 'This is the detailed description.', - 'job_id' => 'abc123_1234567', - 'job_title' => 'Healthcare Assistant (HCA)', - 'job_type' => 'Care at Home', - 'keywords' => 'flexible, Bristol, part-time', - 'locations' => 'Bath, Devizes', - 'role_id' => 'A/52/86', - 'salary' => '32,000.00 per annum', - 'salary_prefix' => 'Basic Salary', - 'status' => 'Part time', - 'summary' => 'This is the short description.', - 'url_alias' => 'healthcare-assistant-aldershot-june17', -]; -``` - ---- - -```php, [.highlight: 5,8,15,21] -$data = [ - 'command' => 'add', - 'username' => 'bobsmith', - 'password' => 'p455w0rd', - 'active_for' => '365', - 'application_email' => 'bob.12345.123@smith.aplitrak.com', - 'branch_address' => '123 Fake St, Bristol, BS1 2AB', - 'branch_name' => 'Test', - 'contract' => 'Temporary', - 'details' => 'This is the detailed description.', - 'job_id' => 'abc123_1234567', - 'job_title' => 'Healthcare Assistant (HCA)', - 'job_type' => 'Care at Home', - 'keywords' => 'flexible, Bristol, part-time', - 'locations' => 'Bath, Devizes', - 'role_id' => 'A/52/86', - 'salary' => '32,000.00 per annum', - 'salary_prefix' => 'Basic Salary', - 'status' => 'Part time', - 'summary' => 'This is the short description.', - 'url_alias' => 'healthcare-assistant-aldershot-june17', -]; -``` - ---- - -## Implementation - -- If no error, create the job node, return OK response to Broadbean -- If an Exception is thrown, return an error code and message - -^ Required field missing Incorrect branch name - ---- - -## Testing Goals - -- Ensure job nodes are **successfully created** -- Ensure that fields are **mapped correctly** -- Ensure that **calculations are correct** -- Ensure that entity references are **linked correctly** - ---- - -## Types of tests - -- **Functional:** job nodes are created with the correct URL and the correct response code is returned -- **FunctionalJavaScript:** application URL is updated with JavaScript based on UTM parameters (hosting) - ---- - -## Types of tests - -- **Kernel:** job nodes can be added and deleted, expired job nodes are deleted, application URL is generated correctly -- **Unit:** ensure number of days are converted to timestamps correctly - ---- - -## Results - -- **0 bugs!** -- Easier to identify where issues occurred and responsibilities -- Reduced debugging time -- Added more tests for any bugs to prevent - ---- - -[.header: alignment(center)] - -## **Running Tests** - ---- - -## Core script - -``` -$ php core/scripts/run-tests.sh - -$ php core/scripts/run-tests.sh --module example - -$ php core/scripts/run-tests.sh --class ExampleTest -``` - ---- - -## PHPUnit - -``` -$ vendor/bin/phpunit \ - -c core \ - modules/contrib/examples/phpunit_example -``` - ---- - -## Prerequisite (creating a phpunit.xml file) - -- Configures PHPUnit -- Needed to run some types of tests -- Ignored by Git by default -- Copy **core/phpunit.xml.dist** to **core/phpunit.xml** -- Add and change as needed - - `SIMPLETEST_BASE_URL`, `SIMPLETEST_DB`, `BROWSERTEST_OUTPUT_DIRECTORY` - - `stopOnFailure="true"` - ---- - -[.header: alignment(center)] - -## **Test Driven
Development** - ---- - -## Test Driven Development - -- Write a test -- Test fails -- Write code -- Test passes -- Refactor -- Repeat - ---- - -[.background-color: #FFFFFF] -[.footer: https://github.com/foundersandcoders/testing-tdd-intro] -[.footer-style: #2F2F2F] - -![100%](images/tdd-loop.png) - ---- - -[.header: alignment(center)] - -## **Red, Green, Refactor** - ---- - -## Porting Modules to Drupal 8 - -- Make a new branch -- Add/update the tests -- Write code to make the tests pass -- Refactor -- Repeat - ---- - -## How I Write Tests - "Outside In" - -- Start with functional tests -- Drop down to integration or unit tests where needed -- Programming by wishful thinking -- Write comments first, then fill in the code -- Sometimes write assertions first - ---- - -[.header: alignment(center)] - -## **Demo: Building a Blog module** - ---- - -## Acceptance criteria - -- As a site visitor -- I want to see a list of published articles at /blog -- Ordered by post date - ---- - -## Tasks - -- Ensure the blog page exists -- Ensure only published articles are shown -- Ensure the articles are shown in the correct order - ---- - -[.background-color: #FFFFFF] - -![140%](images/tawny-tweet-1.png) - ---- - -[.background-color: #FFFFFF] - -![150%](images/tawny-tweet-2.png) - ---- - -[.header: alignment(center)] - -## **TestDrivenDrupal.com** - ---- - -![100%](../images/drupal-association-logo.png) - ---- - -[.header: alignment(center)] - -# **Questions?** - -### @opdavies -### oliverdavies.uk diff --git a/src/test-driven-drupal/todo.md b/src/test-driven-drupal/todo.md deleted file mode 100644 index b8c0252..0000000 --- a/src/test-driven-drupal/todo.md +++ /dev/null @@ -1,2 +0,0 @@ -- Show composer.json setup -- Add "things you can test" and "things you shouldn't test" diff --git a/src/using-laravel-collections-outside-laravel/images/all-the-things.jpg b/src/using-laravel-collections-outside-laravel/images/all-the-things.jpg deleted file mode 100644 index 4817029..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/all-the-things.jpg and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/blog-post.png b/src/using-laravel-collections-outside-laravel/images/blog-post.png deleted file mode 100644 index 9805f99..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/blog-post.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-1.png b/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-1.png deleted file mode 100644 index 5faddee..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-1.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-2.png b/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-2.png deleted file mode 100644 index a5bd958..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/collection-class-module-project-page-2.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/composer.png b/src/using-laravel-collections-outside-laravel/images/composer.png deleted file mode 100644 index bb95a49..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/composer.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/drupal-8.png b/src/using-laravel-collections-outside-laravel/images/drupal-8.png deleted file mode 100644 index a0d7bb9..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/drupal-8.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/drupal-issue-1.png b/src/using-laravel-collections-outside-laravel/images/drupal-issue-1.png deleted file mode 100644 index 1d79637..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/drupal-issue-1.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/drupal-issue-2.png b/src/using-laravel-collections-outside-laravel/images/drupal-issue-2.png deleted file mode 100644 index aabd686..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/drupal-issue-2.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/druplicon.png b/src/using-laravel-collections-outside-laravel/images/druplicon.png deleted file mode 100644 index f8ced55..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/druplicon.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/laravel.png b/src/using-laravel-collections-outside-laravel/images/laravel.png deleted file mode 100644 index 3c83acc..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/laravel.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/packagist.png b/src/using-laravel-collections-outside-laravel/images/packagist.png deleted file mode 100644 index c129ae3..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/packagist.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/tweet-1.png b/src/using-laravel-collections-outside-laravel/images/tweet-1.png deleted file mode 100644 index e58e63f..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/tweet-1.png and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/images/yay-open-source.jpg b/src/using-laravel-collections-outside-laravel/images/yay-open-source.jpg deleted file mode 100644 index ab224d2..0000000 Binary files a/src/using-laravel-collections-outside-laravel/images/yay-open-source.jpg and /dev/null differ diff --git a/src/using-laravel-collections-outside-laravel/slides.md b/src/using-laravel-collections-outside-laravel/slides.md deleted file mode 100644 index 9940e26..0000000 --- a/src/using-laravel-collections-outside-laravel/slides.md +++ /dev/null @@ -1,239 +0,0 @@ -theme: poster, 8 autoscale: true build-lists: true header-emphasis: #53B0EB -header: alignment(left) text: alignment(left) text-emphasis: #53B0EB code: -Operator Mono, line-height(1.5) - -[.background-color: #FFFFFF][.hide-footer] [.header: #111111, alignment(center)] - -## Using Laravel Collections...
Outside Laravel - -![250%](images/laravel.png) - ---- - -[.header: alignment(center)] - -## Collections :thumbsup: - -^ Became a fan of Collections whilst learning Laravel Powerful object orientated -way to interact with arrays Store items within the collection, run methods, -chainable More readable, less temporary variables Video on Laracasts, Adam -Wathan's refactoring to Collections Wanted to use them with different PHP -projects e.g. Drupal - ---- - -```php -collect(['foo', 'bar']); // ['foo', 'bar'] - -collect('foobar'); // ['foobar'] - -$object = new stdClass(); -$object->foo = 'bar'; -collect($object); // ['foo' => 'bar'] -collect($object)->get('foo'); // bar -``` - -^ How do you make a collection? collect function is provided String, array or -object Stored as items within the Collection object - ---- - -```php -$collection = collect(['a', 'b', 1, 'c', 2, 'd', 'e', 3, 4]); - -$collection->count(); // 9 - -$collection->first(); // a - -$collection->first(function ($item) { - return is_numeric($item); -}); // 1 - -$collection->contains(2); // true - -$collection->contains([2, 10]); // false - -$collection->filter(function ($item) { - return $item > 2; -}); // [3, 4] -``` - -^ Once you have a collection, what can you do with it? "contains" - no more -needle/haystack, haystack/needle "filter" - filters false, null values Can pass -callbacks to `first` and `filter`, return true or false as needed. - ---- - -```php -$collection = collect([ - ['name' => 'John', 'email' => 'john@example.com', 'age' => 31], - ['name' => 'Jane', 'email' => 'jane@example.com', 'age' => 27], -]); - -$collection->pluck('name'); // ['John', 'Jane'] - -$collection->pluck('name')->sort(); // ['Jane', 'John'] - -$collection->filter(function ($person) { - return $person['age'] >= 30; -})->pluck('name'); // ['John'] -``` - ---- - -[.background-color: #FFFFFF] - -![100%](images/druplicon.png) - -^ This is great, but how can I do that in my Drupal code? How can I do that? - ---- - -## There’s a module for that! - -### _- Drupalers_ - ---- - -[.text: alignment(center)] - -## [fit] There's not a module for that. :disappointed: - -### _- Me_ - ---- - -![fit](images/collection-class-module-project-page-1.png) - -^ Drupal 7 - ---- - -### _Version 1.0_ - -## Write my own Collection class - -^ Wrote my own Collection class Wrote my own tests - ---- - -![](images/drupal-issue-1.png) - -^ Maybe 70% of what Laravel's could do. - ---- - -![](images/packagist.png) - -^ Can't remember how, but then I found this. - ---- - -### Collect - Illuminate Collections as a separate package. - -#### _https://packagist.org/packages/tightenco/collect_ - ---- - -### Import Laravel's Collections into non-Laravel packages easily, without needing to require the entire Illuminate\Support package. - -#### _https://packagist.org/packages/tightenco/collect_ - ---- - -[.background-color: #FFFFFF] - -![600%](images/composer.png) - -^ Can install via Composer - ---- - -## _composer require_
tightenco/collect - ---- - -![](images/drupal-issue-2.png) - ---- - -![fit](images/collection-class-module-project-page-2.png) - ---- - -### _Version 2.0_ - -## Use someone else’s Collection class - -^ More fully featured, less code to maintain - ---- - -[.background-color: #FFFFFF] - -![120%](images/yay-open-source.jpg) - ---- - -[.build-lists: false] - -- Install Composer -- Require `tightenco/collect` -- Include `autoload.php` -- `collect()` away! - ---- - -[.build-lists: false] - -- Install Composer -- Require `tightenco/collect` -- Include `autoload.php` -- `collect()` away! - -![100%](images/drupal-8.png) - ---- - -```php -// index.php - -require __DIR__ . '/vendor/autoload.php'; - -$collection = collect(['foo', 'bar']); - -$collection->each(function ($item) { - // Do something. -}); -``` - -^ Require/include autoload.php Start using Collections! `collect` function is -autoloaded - ---- - -[.background-color: #FFFFFF] - -![150%](images/all-the-things.jpg) - -^ Drupal 8, Sculpin site, PHP libraries - ---- - -[.background-color: #FFFFFF] - -![inline](images/tweet-1.png) - ---- - -![inline](images/blog-post.png) - ---- - -[.header: alignment(center)] - -# Thanks! - -### _@opdavies_ - -### _oliverdavies.uk_