https://github.com/lullabot/drainpipe
https://github.com/lullabot/drainpipe
Last synced: about 2 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/lullabot/drainpipe
- Owner: Lullabot
- License: gpl-3.0
- Created: 2021-05-17T13:55:52.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2025-04-23T19:27:26.000Z (about 1 year ago)
- Last Synced: 2025-04-24T06:54:09.049Z (about 1 year ago)
- Language: PHP
- Size: 85.7 MB
- Stars: 36
- Watchers: 9
- Forks: 14
- Open Issues: 67
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-ddev - Drainpipe - dev): Drainpipe is a composer package which provides a number of build tool helpers for a Drupal site, including several DDEV integrations for local development and CI testing (includes selenium + chrome + firefox testing). (Tools)
README
# Drainpipe
Drainpipe is a composer package which provides build tool and testing helpers
for a Drupal site, including:
- Site and database updates
- Artifact packaging for deployment to a hosting provider
- Automated testing setup
- Integration with DDEV
- CI integration
## Installation
```sh
composer config extra.drupal-scaffold.gitignore true
composer config --json extra.drupal-scaffold.allowed-packages "[\"lullabot/drainpipe\", \"lullabot/drainpipe-dev\"]"
composer require lullabot/drainpipe
composer require lullabot/drainpipe-dev --dev
```
and if using DDEV, restart to enable the added features:
```sh
ddev restart
```
### Taskfile
Drainpipe will scaffold out various files, most importantly a `Taskfile.yml` in
the root of your repository. [Task](https://taskfile.dev/) is a task runner / build tool
that aims to be simpler and easier to use than, for example, GNU Make. Since
it's written in Go, Task is just a single binary and has no other dependencies.
It's also cross-platform with everything running through the same [shell interpreter](https://github.com/mvdan/sh).
Drainpipe installs the Task binary for you, no matter if you are using DDEV or
not. If you already have Task installed system-wide and are not using DDEV, your
installed binary will be linked from the `vendor/bin` directory.
You can see which tasks are available after installation by running
`./vendor/bin/task --list` or `ddev task --list` if you're running DDEV. To get
more information on a specific task e.g. what parameters it takes, you can run
`task [task name] --summary`.
Your `Taskfile.yml` can be validated with JSON Schema:
```
curl -O https://taskfile.dev/schema.json
npx ajv-cli validate -s schema.json -d scaffold/Taskfile.yml
```
See [`.github/workflows/ValidateTaskfile.yml`](.github/workflows/ValidateTaskfile.yml)
for an example of this in use.
### Overriding files provided by drainpipe
Drupal scaffolds are core files automatically placed and updated in the project
root by `drupal/core-composer-scaffold` ([documentation](https://www.drupal.org/docs/develop/using-composer/using-drupals-composer-scaffold#toc_4)).
Scaffold files provided by Drainpipe are located in the main `scaffold` directory.
To determine where a file is placed, edit the `extra.drupal-scaffold` section in
`composer.json`. Check how each scaffolded file is defined in `/src/ScaffoldInstallerPlugin.php`.
A specific file scaffolding can be disabled by mapping it to false under the
`extra.drupal-scaffold.file-mapping` in the project `composer.json` file. This
prevents it from being created or overriden when running `composer install` or
`composer update`. Note Drainpipe workflows cannot be overridden.
```
{
"extra": {
"drupal-scaffold": {
"file-mapping": {
"[web-root]/robots.txt": false
}
}
}
}
```
### Binaries
If you receive an error such as `exec format error: ./vendor/bin/task`, then
you may have the wrong binary for your architecture. If your architecture
wasn't detected correctly, please open an issue with the output of `php -r "echo php_uname('m');"`,
along with information on your hardware and operating system.
You can override the platform and processor with environment variables `DRAINPIPE_PLATFORM`
and `DRAINPIPE_PROCESSOR`. Valid platform values are `linux`, `darwin`, or `windows`,
and processors are `386`, `amd64`, or `arm64`. These correspond to builds of
upstream dependencies e.g. https://github.com/go-task/task/releases
### Tugboat
The Tugboat configuration file is not a static file; it is dynamically generated
based on your `.ddev/config.yaml` file. To see the implementation details, check
[/src/TugboatConfigPlugin.php](https://github.com/Lullabot/drainpipe/blob/main/src/TugboatConfigPlugin.php).
### Node JS
All Drainpipe components (DDEV, Github Actions, Tugboat) are configured to use
the same Node JS major version. This is set in the `.nvmrc` file, which is
scaffolded from the Drainpipe's root directory, but can be overriden to use a
different Node version.
## Renovate Presets
If you are using [Renovate](https://docs.renovatebot.com/) (for automated dependency updates) you can use/extend our Drupal presets by doing the following:
```
{
"extends": [
"group:drupal-core"
]
}
```
This preset provides safe automation with flexibility and control for teams maintaining Drupal applications, minimizing risk by requiring approval for major changes while accelerating security patches through the automerging of minor updates.
## Database Updates
The `drupal:update` command runs [`drush deploy`](https://www.drush.org/12.x/deploycommand/)
directly, per the [Lullabot ADR on Drupal build steps](https://architecture.lullabot.com/adr/20260313-drupal-build-steps/).
```
drush deploy
```
Sites that need to customize the deploy steps (e.g. running `config:import`
twice, or running `drush cron` after deploy) should replace the `drush deploy`
command using a site-level Drush command file. See the
[ADR](https://architecture.lullabot.com/adr/20260313-drupal-build-steps/) for a
full example.
## .env support
Drainpipe will add `.env` file support for managing environment variables.
**This is only used for locals** - other environments such as CI and production
should use their native environment variable mechanisms.
This consists of:
- Creation of a `.env` and `.env.defaults` file
- Default `Taskfile.yml` contains [dotenv support](https://taskfile.dev/usage/#env-files)
_note: real environment variables will override these_
- Drupal integration via [`vlucas/phpdotenv`](https://packagist.org/packages/vlucas/phpdotenv)
To enable this, add the following to your `composer.json`:
```
"autoload-dev":
{
"files": [
"vendor/lullabot/drainpipe/scaffold/env/dotenv.php"
]
},
```
**You will need to restart DDEV if you make any changes to `.env` or`.env.defaults`**
## SASS Compilation
This compiles CSS assets using [Sass](https://sass-lang.com/). It also supports
the following:
- Globbing
```
// Base
@use "sass/base/**/*";
```
- [Modern Normalizer](https://www.npmjs.com/package/modern-normalize)
- Autoprefixer configured through a [`.browserslistrc`](https://github.com/postcss/autoprefixer)
file in the project root
### Setup
- Add @lullabot/drainpipe-sass to your project
`yarn add @lullabot/drainpipe-sass` or `npm install @lullabot/drainpipe-sass`
- Edit `Taskfile.yml` and add `DRAINPIPE_SASS` in the `vars` section
```
vars:
DRAINPIPE_SASS: |
web/themes/custom/mytheme/style.scss:web/themes/custom/mytheme/style.css
web/themes/custom/myothertheme/style.scss:web/themes/custom/myothertheme/style.css
```
- Run `task sass:compile` to check it works as expected
- Run `task sass:watch` to check file watching works as expected
- Add the task to a task that compiles all your assets e.g.
```
assets:
desc: Builds assets such as CSS & JS
cmds:
- yarn install --immutable --immutable-cache --check-cache
- task: sass:compile
- task: javascript:compile
assets:watch:
desc: Builds assets such as CSS & JS, and watches them for changes
deps: [sass:watch, javascript:watch]
```
## JavaScript Compilation
JavaScript bundling support is via [esbuild](https://esbuild.github.io/).
### Setup
- Add @lullabot/drainpipe-javascript to your project
`yarn add @lullabot/drainpipe-javascript` or `npm install @lullabot/drainpipe-javascript`
- Edit `Taskfile.yml` and add `DRAINPIPE_JAVASCRIPT` in the `vars section`
```
DRAINPIPE_JAVASCRIPT: |
web/themes/custom/mytheme/script.js:web/themes/custom/mytheme/script.min.js
web/themes/custom/myotherthemee/script.js:web/themes/custom/myothertheme/script.min.js
```
Source and target need to have the same basedir (web or docroot) due to being
unable to provide separate entryNames.
See https://github.com/evanw/esbuild/issues/224
- Run `task javascript:compile` to check it works as expected
- Run `task javascript:watch` to check file watching works as expected
- Add the task to a task that compiles all your assets e.g.
```
assets:
desc: Builds assets such as CSS & JS
cmds:
- yarn install --immutable --immutable-cache --check-cache
- task: sass:compile
- task: javascript:compile
assets:watch:
desc: Builds assets such as CSS & JS, and watches them for changes
deps: [sass:watch, javascript:watch]
```
## Testing
This is provided by the separate [drainpipe-dev](https://github.com/Lullabot/drainpipe-dev)
package (so the development/testing dependencies aren't installed in production
builds).
### Static Tests
All the below static code analysis tests can be run with `task test:static`
| Test Type | Task Command | Description |
|-----------|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Security | task test:security | Runs security checks for composer packages against the [FriendsOfPHP Security Advisory Database](https://github.com/FriendsOfPHP/security-advisories) and Drupal core and contributed modules against [Drupal's Security Advisories](https://www.drupal.org/security). |
| Lint | task test:lint | - YAML lint on `.yml` files in the `web` directory
- Twig lint on files in `web/modules`, `web/profiles`, and `web/themes`
- `composer validate`
These cannot currently be customised. See [#9](https://github.com/Lullabot/drainpipe-dev/issues/9). |
| PHPStan | task test:phpstan | Runs [PHPStan](https://phpstan.org/) with [mglaman/phpstan-drupal](https://github.com/mglaman/phpstan-drupal) on `web/modules/custom`, `web/themes/custom`, and `web/sites` at level 6. |
| PHPUnit | task test:phpunit:static | Runs Unit tests in `web/modules/custom/**/tests/src/Unit` and `test/phpunit/**/Unit` |
| PHPCS | task test:phpcs | Runs PHPCS with Drupal coding standards provided by [Coder module](https://www.drupal.org/project/coder |
#### PHPStan Baseline for Existing Codebases
Projects with pre-existing violations can generate a baseline file to suppress
them, so CI only fails on new code:
```
task test:phpstan:generate-baseline
git add phpstan.neon phpstan-baseline.neon
git commit -m "Add PHPStan level 6 baseline"
```
This creates `phpstan-baseline.neon` (the suppressed violations) and
`phpstan.neon` (which includes both `phpstan.neon.dist` and the baseline).
Commit both files. The baseline can be regenerated at any time as legacy
violations are resolved.
#### Altering PHP_CodeSniffer Configuration
- Create `phpcs.xml` to override the `phpcs.xml.dist` file with overrides being done in:
```
```
- Edit `phpcs.xml` in the root of your project, e.g. to add an exclude pattern:
```
web/sites/sites.php
```
### Functional Tests
Functional tests require some mechanism of creating a functing Drupal site to
test against. All the below tests can be run with `task test:functional`
#### PHPUnit
`task test:phpunit:functional`
Runs PHPUnit tests in:
- `web/modules/custom/**/tests/src/Kernel`
- `test/phpunit/**/Kernel`
- `web/modules/custom/**/tests/src/Functional`
- `test/phpunit/**/Functional`
- `web/modules/custom/**/tests/src/FunctionalJavaScript`
- `test/phpunit/**/FunctionalJavaScript`
You will need to make sure you have a working Drupal site before you're
able to run these.
### Autofix
`task test:autofix` attempts to autofix any issues discovered by tests.
Currently, this is just fixing PHPCS errors with PHPCBF.
## Hosting Provider Integration
### Generic
Generic helpers for deployments can be found in [`tasks/snapshot.yml`,](tasks/snapshot.yml)
[`tasks/deploy.yml`](tasks/deploy.yml), and [`tasks/drupal.yml`](tasks/drupal.yml)
| | |
|------------------------------------|-------------------------------------------------------------------------------|
| `task deploy:git` | Pushes a directory to a git remote |
| `task drupal:composer:development` | Install composer dependencies |
| `task drupal:composer:production` | Install composer dependencies without devDependencies |
| `task drupal:export-db` | Exports a database fetched with a *:fetch-db command |
| `task drupal:import-db` | Imports a database fetched with a *:fetch-db command |
| `task drupal:install` | Runs the site installer |
| `task drupal:maintenance:off` | Turn off Maintenance Mode |
| `task drupal:maintenance:on` | Turn on Maintenance Mode |
| `task drupal:update` | Run Drupal update tasks after deploying new code |
| `task snapshot:archive` | Creates a snapshot of the current working directory and exports as an archive |
| `task snapshot:directory` | Creates a snapshot of the current working directory |
#### Importing/Exporting Databases
Databases are by default fetched to `/var/www/html/files/db/db.sql.gz`, this can
be overridden with a [variable](https://taskfile.dev/usage/#variables) in Task:
```
`task drupal:import-db DB_DIR="/var/www/htdocs"`
```
#### Snapshots
When creating a snapshot of the current working directly files can be excluded
using a `.drainpipeignore` file in the root of the repository that uses the same
format as `.gitignore`, e.g.
```
# Files that won't be deployed to Pantheon
/.ddev
/.github
/.yarn
/files/db
/tests
/.env
/.env.defaults
/README.md
/Taskfile.yml
*.sql
*.sql.gz
```
This folder can then be deployed to a remote service either as an archive, or
pushed to a git remote with `task deploy:git`.
### Pantheon
Pantheon specific tasks are contained in [`tasks/pantheon.yml`](tasks/pantheon.yml).
Add the following to your `Taskfile.yml`'s `includes` section to use them:
```yml
includes:
pantheon: ./vendor/lullabot/drainpipe/tasks/pantheon.yml
```
| | |
|--------------------------|-----------------------------------------------------------------------------|
| `task pantheon:fetch-db` | Fetches a database from Pantheon. Set `PANTHEON_SITE_ID` in Taskfile `vars` |
| | and optionally `ENVIRONMENT` to override the default value of `live` |
See below for CI specific integrations for hosting providers.
When using Pantheon with Drainpipe, the Pantheon site should be configured to
override some of Pantheon's default behaviors. Because Drainpipe installs
composer dependencies, Pantheon's [Integrated Composer](https://docs.pantheon.io/guides/integrated-composer)
should be disabled. Add `build_step: false` to your pantheon.yml file:
```yml
---
api_version: 1
build_step: false
```
Additionally, Pantheon sites start with "[Autopilot](https://docs.pantheon.io/guides/autopilot)",
which provides updates from the Drupal upstream. Usually this feature
conflicts with an external Git repository such as GitHub or GitLab. It is
recommended to disable this by setting an empty upstream with terminus.
```
ddev ssh
terminus site:upstream:set [site_name] empty
```
#### Pantheon Systems: Drupal Integrations
`pantheon-systems/drupal-integrations` is a package that provides essential Pantheon functionality. It is strongly recommended to install it.
```
composer require pantheon-systems/drupal-integrations
```
### Acquia
Acquia specific tasks are contained in [`tasks/acquia.yml`](tasks/acquia.yml).
Add the following to your `Taskfile.yml`'s `includes` section to use them:
```yml
includes:
acquia: ./vendor/lullabot/drainpipe/tasks/acquia.yml
```
| | |
|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `task acquia:fetch-db` | Fetches a database from Acquia. Set `ACQUIA_ENVIRONMENT_ID` in Taskfile `vars`, along with `ACQUIA_API_KEY` and `ACQUIA_API_SECRET` as environment variables |
> ⚠️ **Beta Notice**: The Acquia integration is currently in beta. While we strive to maintain stability, you may encounter unexpected issues. Please report any problems you encounter through our issue tracker.
To enable auto configuration of Acquia Cloud settings:
```json
"extra": {
"drainpipe": {
"acquia": {
"settings": true
},
}
}
```
## GitHub Actions Integration
Add the following to `composer.json` for generic GitHub Actions that will be
copied to `.github/actions/drainpipe` in your project:
```json
"extra": {
"drainpipe": {
"github": []
}
}
```
They are composite actions which can be used in any of your workflows e.g.
```
- uses: ./.github/actions/drainpipe/set-env
- name: Install and Start DDEV
uses: ./.github/actions/drainpipe/ddev
with:
git-name: Drainpipe Bot
git-email: no-reply@example.com
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
ssh-known-hosts: ${{ secrets.SSH_KNOWN_HOSTS }}
```
Tests can be run locally with [act](https://github.com/nektos/act):
```
# Turn off ddev so it doesn't get confused between your real host and the
# "host" inside of act. Do this again and when done and you want to run
# the app on your host again.
ddev poweroff
# Windows
act -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest -j Static-Tests
# Mac with Docker Desktop
act --container-options "--group-add $(stat -f %g /var/run/docker.sock)" \
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest \
-j Static-Tests
# Mac with OrbStack
export DOCKER_HOST=$(docker context inspect --format '{{.Endpoints.docker.Host}}')
act --container-options "--group-add $(stat -f %g ~/.orbstack/run/docker.sock)" \
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest \
-j Static-Tests
# Mac with Lima
# Act gets confused with socket permissions. Run act from inside the lima VM.
# Run `lima` to shell into the VM, then install act following the docs or from
# https://github.com/nektos/act/releases.
# As well, comment out the chown in `.github/actions/drainpipe/ddev/action.yml`.
act --container-options "--group-add $(stat -c %g /var/run/docker.sock)" \
-P ubuntu-latestt=ghcr.io/catthehacker/ubuntu:runner-latest \
-j Static-Tests
# Linux
act --container-options "--group-add $(stat -c %g /var/run/docker.sock)" \
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:runner-latest \
-j Static-Tests
# Using an alternate image like WarpBuild
`-P warp-ubuntu-latest-x64-2x-spot=ghcr.io/catthehacker/ubuntu:runner-latest`.
```
### Tests
Workflows for running static and functional tests can be added with the following
configuration:
```json
"extra": {
"drainpipe": {
"github": ["TestStatic", "TestFunctional"]
}
}
```
The build process for the functional tests will use `task build:ci:functional`,
falling back to `task build:dev`, and then `task build`. The static tests
should not require a build step.
These workflow files will continue to be managed by Drainpipe and cannot be
overridden. If you wish to do so then it's recommended you maintain your own
workflows for testing.
### Security
```json
"extra": {
"drainpipe": {
"github": ["Security"]
}
}
```
Runs security checks for composer packages and Drupal contrib, as well as posting
a diff of `composer.lock` as a review comment.
Security checks rely on `composer audit`. This means `test:security` task will
exit with error if your dependencies have known vulnerabilities. Sometimes, this
is not desirable: think of a component which is required by Drupal core - you
can not upgrade it directly, because it is pinned to a specific version by Drupal
in the first place. To prevent these kind of situations from failing the security
check, you can configure `composer audit` to ignore specific vulnerabilities
when scanning your dependencies. To do so, the simplest way is to modify your
`composer.json` file to add a list of vulnerabilities that should not trigger an
error when running `test:security`:
```json
"config": {
"audit": {
"ignore": ["CVE-1234", "GHSA-xx", "PKSA-yy"]
}
}
```
For more details about how to configure the ignore feature for `composer audit`,
check the [Composer docs](https://getcomposer.org/doc/06-config.md#ignore).
The Security workflow also includes a [Zizmor](https://woodruffw.github.io/zizmor/)
static analysis job (`ZizmorAnalysis`) that scans your GitHub Actions workflow
files for security issues. Zizmor results are uploaded to GitHub's code scanning
dashboard, which requires [Code Security](https://docs.github.com/en/code-security/getting-started/github-security-features)
to be enabled for your repository. If it is not enabled, the `ZizmorAnalysis`
job will fail with: _"Code Security must be enabled for this repository to use
code scanning."_
The Security workflow also includes a [Gitleaks](https://github.com/gitleaks/gitleaks)
job (`Gitleaks`) that scans every PR and push to the default branch for accidentally
committed secrets — API keys, tokens, credentials, and similar sensitive values.
Findings are uploaded to GitHub's code scanning dashboard under the **Gitleaks**
category.
**Suppressing false positives**: Drainpipe scaffolds a `.gitleaks.toml` at the
project root that pre-configures allowlists for patterns common in Drupal
projects (contributed modules, Drupal core, GitHub Actions template expressions,
and placeholder values). Add `[[allowlists]]` blocks to that file to suppress
additional false positives specific to your project. Use `[extend]` with
`useDefault = true` to inherit all default rules and layer your allowlists on top:
```toml
[[allowlists]]
description = "Allow example values in documentation"
regexes = [
'''(?i)example''',
'''(?i)replace[-_.]?me''',
]
[[allowlists]]
description = "Allow test fixtures"
paths = [
'''tests/fixtures/''',
]
```
**Recommended: one-time full history scan**: When first adopting Gitleaks, run a
scan of your full git history to check for secrets that may already be committed:
```sh
# Ensure you have a full clone (not shallow)
git fetch --unshallow
# Scan full history and save results to a JSON report
gitleaks detect --source . --report-format json --report-path gitleaks-history.json
```
Review `gitleaks-history.json` and for each finding: rotate any credentials that
are still valid; for false positives, add the pattern to `.gitleaks.toml`. Note
that rewriting git history to remove secrets is disruptive — rotating the
credential is the most effective remediation.
### NPM & Yarn Lockfile Diff
Post a sticky comment in the Pull Request with a markdown table of any changes
detected in `yarn.lock` or `package-lock.json` files.
```json
"extra": {
"drainpipe": {
"github": ["LockfileDiff"]
}
}
```
### Pantheon
To scaffold Pantheon composite actions for use in your own workflows (without a managed review app
workflow), add `"Actions"`:
```json
"extra": {
"drainpipe": {
"github": {
"pantheon": ["Actions"]
}
}
}
```
This scaffolds `.github/actions/drainpipe/pantheon/` (setup-terminus, push, clone-env, update,
review) along with `pantheon.yml` and `.drainpipeignore`, without installing any workflow file.
Use this when you manage your own deployment workflow and want Drainpipe's composite actions as
building blocks.
To enable deployment of Pantheon Review Apps (Multidev environments per pull request):
- Add the following to `composer.json`:
```json
"extra": {
"drainpipe": {
"github": {
"pantheon": ["ReviewApps"]
}
}
}
```
`ReviewApps` implicitly includes `Actions` — you do not need to list both.
- Run `composer install` to install the workflow to `.github/workflows`
- [Create a `build multidev` label](https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/managing-labels#creating-a-label)
in your GitHub repository. The workflow triggers when this label is added to a pull request,
and re-runs on subsequent commits while the label is present.
- If you want the multidev build to run on **every** pull request automatically, add the
`build multidev` label to your [pull request template](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository).
- Add the following [variables to your GitHub repository](https://docs.github.com/en/actions/learn-github-actions/variables#creating-configuration-variables-for-a-repository):
- `PANTHEON_SITE_NAME` The canonical site name in Pantheon
- `TERMINUS_PLUGINS` (optional) Comma-separated list of Terminus plugins to be available
- `TERMINUS_TIMEOUT_LIMIT` (optional) Number of seconds that terminus will wait until timeout. Defaults to 600
- `PANTHEON_CLONE_FROM` (optional) The environment to clone from when creating multidev sites. Defaults to 'live'
- `PANTHEON_SKIP_WIPE_MULTIDEV` (optional) Set to 'true' to skip wiping the multidev environment on each push, preserving its database state. Defaults to 'false'
- Add the following [secrets to your GitHub repository](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/managing-development-environment-secrets-for-your-repository-or-organization#adding-secrets-for-a-repository):
- `TERMINUS_MACHINE_TOKEN` See https://pantheon.io/docs/terminus/install#machine-token
- `SSH_PRIVATE_KEY` A private key of a user which can push to Pantheon
- `SSH_KNOWN_HOSTS` The result of running `ssh-keyscan -H -p 2222 codeserver.dev.$PANTHEON_SITE_ID.drush.in`
- `PANTHEON_REVIEW_USERNAME` (optional) A username for HTTP basic auth
- `PANTHEON_REVIEW_PASSWORD` (optional) The password to lock the site with
- `PANTHEON_REVIEW_RUN_INSTALLER` (optional) Set to `"true"` to run `site:install --existing-config` instead of `drupal:update` when deploying
### Acquia
To add Acquia specific GitHub actions, add the following to `composer.json`:
```json
"extra": {
"drainpipe": {
"github": {
"acquia": ["Deploy"]
}
}
}
```
Then run `composer install`. A Deploy to Acquia workflow at `.github/workflows/AcquiaDeploy.yml` will be added (with its dependent actions).
After the Github Actions Integration is merged, you can deploy to Acquia using the UI or the Github CLI (gh).
**Github repository settings**
In your Github repository settings you need to create the following:
- Repository Variables
- To identify the project we are deploying (same value of the AH_SITE_GROUP environment value)
- ACQUIA_SITE_GROUP
- Repository Secrets
- To use Acquia CLI (acli) to interact with [Acquia's Cloud Platform](https://docs.acquia.com/acquia-cloud-platform/add-ons/acquia-cli/start)
- ACQUIA_API_KEY
- ACQUIA_API_SECRET
- To push code to your Acquia repository
- ACQUIA_SSH_PRIVATE_KEY
**Task settings**
When a deployment is made, you must run your own code _before_ and _after_ the deployment. To do so, define your in your `/Taskfile.yml` the following:
- **acquia:deploy:before**
```
acquia:deploy:before
desc: "Before the code is deployed to Acquia, run these commands on the GitHub Actions runner"
cmds:
# This task is run on the GitHub Actions runner
# It is a good moment to run tasks like build
# so we can later create the artifact for the Acquia environment.
- task: build
```
- **acquia:deploy:after**
Runs after the code is switched on the Acquia environment and before
`drupal:update` is called automatically by Drainpipe. Use this for any steps
that must happen between the code switch and the Drupal update, such as
enabling maintenance mode or syncing files from another environment.
```
acquia:deploy:after:
desc: "After the code is switched on the Acquia environment, run these commands"
cmds:
# This task runs on the Acquia environment. The site alias is passed
# automatically so commands like drush run against the correct environment.
- task: drupal:maintenance:on
```
## GitLab CI Integration
Add the following to `composer.json` for GitLab helpers:
```json
"extra": {
"drainpipe": {
"gitlab": []
}
}
```
This will import [`scaffold/gitlab/Common.gitlab-ci.yml`](scaffold/gitlab/Common.gitlab-ci.yml),
which provides helpers that can be used in GitLab CI with [includes and
references](https://docs.gitlab.com/ee/ci/yaml/yaml_specific_features.html#reference-tags),
or `scaffold/gitlab/DDEV.gitlab-ci.yml` if you are using DDEV.
```
include:
- local: '.gitlab/drainpipe/DDEV.gitlab-ci.ymll'
variables:
DRAINPIPE_DDEV_GIT_EMAIL: drainpipe-bot@example.com
DRAINPIPE_DDEV_GIT_NAME: Drainpipe Bot
build:
stage: build
interruptible: true
script:
- !reference [.drainpipe_setup_ddev, script]
- composer install
- ddev restart
- ddev drush site:install minimal -y
- echo "\$settings['config_sync_directory'] = '../config';" >> web/sites/default/settings.php
- ddev drush config:export -y
- ddev task update
```
Available variables are:
| Variable | |
|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------|
| DRAINPIPE_DDEV_SSH_PRIVATE_KEY | SSH private key used for e.g. committing to git |
| DRAINPIPE_DDEV_SSH_KNOWN_HOSTS | The result of running e.g. `ssh-keyscan -H -p 2222 codeserver.dev.$PANTHEON_SITE_ID.drush.in` |
| DRAINPIPE_DDEV_GIT_EMAIL | E-mail address to use for git commits |
| DRAINPIPE_DDEV_GIT_NAME | Name to use for git commits |
| DRAINPIPE_DDEV_COMPOSER_CACHE_DIR | Set to "false" to disable composer cache dir, or another value to override the default location of .ddev/.drainpipe-composer-cache |
| DRAINPIPE_DDEV_VERSION | Install a specific version of DDEV instead of the latest |
### Security
Runs `composer audit` and posts a composer lock diff as a merge request comment.
Requires `GITLAB_ACCESS_TOKEN` variable to be set with `api` scope.
```json
"extra": {
"drainpipe": {
"gitlab": ["Security"]
}
}
```
### Pantheon
To enable deployment of Pantheon Review Apps (Multidev environments per merge request):
- Add the following to `composer.json`:
```json
"extra": {
"drainpipe": {
"gitlab": {
"pantheon": ["Deploy", "ReviewApps"]
}
}
}
```
Use `"Deploy"` alone if you only want the Terminus setup helpers without the full review app
pipeline. Use both `"Deploy"` and `"ReviewApps"` for full Multidev support.
- Run `composer install` to install the CI files to `.drainpipe/gitlab/`. If no `.gitlab-ci.yml`
exists, an example one will be created for you.
- Add the following [variables to your GitLab repository](https://docs.gitlab.com/ee/ci/variables/#for-a-project):
- `PANTHEON_SITE_NAME` The canonical site name in Pantheon
- `PANTHEON_SITE_ID` The Pantheon site UUID, used to construct the SSH remote URL
- `PANTHEON_GIT_REMOTE` The Pantheon git remote URL e.g. `ssh://codeserver.dev.$PANTHEON_SITE_ID@codeserver.dev.$PANTHEON_SITE_ID.drush.in:2222/~/repository.git`
- `TERMINUS_MACHINE_TOKEN` See https://pantheon.io/docs/terminus/install#machine-token (enable the _Mask variable_ checkbox)
- `SSH_PRIVATE_KEY` A private key of a user which can push to Pantheon (enable the _Mask variable_ checkbox)
- `SSH_KNOWN_HOSTS` The result of running `ssh-keyscan -H -p 2222 codeserver.dev.$PANTHEON_SITE_ID.drush.in` (enable the _Mask variable_ checkbox)
- `GIT_EMAIL` Email address to use for git commits
- `GIT_USERNAME` Username to use for git commits
- `GITLAB_ACCESS_TOKEN` A GitLab access token with `api` scope, used by the scheduled multidev cleanup job
- `TERMINUS_PLUGINS` (optional) Comma-separated list of Terminus plugins to be available
- `REVIEW_APP_BASIC_AUTH` (optional) Basic auth credentials prepended to the review app URL e.g. `user:password@`
- `PANTHEON_MULTIDEV_RUN_INSTALLER` (optional) Set to `"true"` to run `site:install --existing-config` instead of `drupal:update` when deploying
This will setup Merge Request deployment to Pantheon Multidev environments. See
[scaffold/gitlab/gitlab-ci.example.yml] for an example. You can also just
include `"Deploy"` which will give you helpers that you can include and reference for tasks
such as setting up [Terminus](https://pantheon.io/docs/terminus). See
[scaffold/gitlab/Pantheon.gitlab-ci.yml](scaffold/gitlab/Pantheon.gitlab-ci.yml).
## Bitbucket Pipelines Integration
Add the following to `composer.json` to enable Bitbucket Pipelines support:
```json
"extra": {
"drainpipe": {
"bitbucket": []
}
}
```
### PHP extensions
The pipeline image (`php:8.5-cli`) includes only a minimal set of PHP extensions. Before running `composer install`, `setup-php.sh` automatically detects missing extensions by running `composer check-platform-reqs` against `composer.lock` and installs them via [`mlocati/docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer).
To ensure an extension is installed, declare it in the `require` block of your project's `composer.json`:
```json
"require": {
"ext-zip": "*",
"ext-gd": "*"
}
```
To identify which extensions your project needs, run:
```
ddev composer check-platform-reqs
```
For extensions that cannot be declared in `composer.json` (e.g. proprietary agents such as New Relic or Tideways), set the `DRAINPIPE_PHP_EXTENSIONS` Bitbucket repository variable to a space-separated list of extension names:
```
newrelic tideways_xhprof
```
### Acquia Deploy
Acquia Deploy triggers a deployment to the Acquia `dev` environment whenever a PR is merged to `main`, equivalent to the GitHub Actions `AcquiaDeploy` workflow.
To enable Acquia Deploy on Bitbucket:
- Add the following to `composer.json`:
```json
"extra": {
"drainpipe": {
"bitbucket": ["AcquiaDeploy"],
"acquia": { "settings": true }
}
}
```
If your main branch is named `master` (or anything other than `main`), set `bitbucketDeployBranch`:
```json
"extra": {
"drainpipe": {
"bitbucket": ["AcquiaDeploy"],
"bitbucketDeployBranch": "master",
"acquia": { "settings": true }
}
}
```
If you are using both Acquia Review Apps and Acquia Deploy, list them together:
```json
"bitbucket": ["AcquiaReviewApps", "AcquiaDeploy"]
```
- Run `composer install` to scaffold the following files into your project:
- `bitbucket-pipelines.yml` — generated at the repository root and kept up to date on every `composer install`. Do not edit this file manually — changes will be overwritten.
- `Taskfile.yml` — a `bitbucket` include pointing to `vendor/lullabot/drainpipe/tasks/bitbucket.yml` is auto-injected
**How it works**
When a PR is merged to `main` the `branches.main` pipeline:
1. Installs system dependencies and configures SSH
2. Runs `composer install`
3. Installs Acquia CLI and authenticates (`task bitbucket:acquia:setup`)
4. Runs the pre-deploy build hook if defined (`task bitbucket:acquia:build` → `task acquia:deploy:before`)
5. Resolves the VCS branch and remote that the Acquia `dev` environment tracks, pushes code via `task deploy:git`, and waits for the code switch to complete (`task bitbucket:acquia:push-dev`)
6. Downloads Drush aliases, runs `task acquia:deploy:after` (if defined), then `task update` or `task drupal:update`, clears caches on all domains, and posts a commit status (`task bitbucket:acquia:update-dev`)
**User-defined hooks**
Add these tasks to your project's `Taskfile.yml` as needed:
```yaml
tasks:
acquia:deploy:before:
desc: "Runs before the Acquia deploy snapshot — compile assets, etc. Do NOT call drupal:composer:production here."
cmds:
- task: build
acquia:deploy:after:
desc: "Runs after code is switched on Acquia — typically calls 'task drupal:update'"
cmds:
- task: drupal:update
vars:
site: "{{.site}}"
```
**Bitbucket repository variables**
Add these in your Bitbucket repository settings under **Repository variables**:
| Variable | Secured | Description |
|---|---|---|
| `ACQUIA_API_KEY` | Yes | Acquia API Key |
| `ACQUIA_API_SECRET` | Yes | Acquia API Secret |
| `ACQUIA_SSH_PRIVATE_KEY` | Yes | SSH private key (base64-encoded) with Acquia Git access |
| `ACQUIA_SITE_GROUP` | No | Application/site group name (e.g. `mysite` from `mysite.dev`) |
| `BITBUCKET_USERNAME` | No | Bitbucket username — required for commit status API calls |
| `BITBUCKET_APP_PASSWORD` | Yes | Bitbucket App Password with `pullrequest:read` scope — required for commit status |
| `DRAINPIPE_PHP_EXTENSIONS` | No | Space-separated list of additional PHP extensions to install beyond those declared in `composer.json` (see [PHP extensions](#php-extensions)) |
> Note: `BITBUCKET_COMMIT` is injected automatically by Bitbucket Pipelines and does not need to be set manually.
> Note: When both `AcquiaReviewApps` and `AcquiaDeploy` are configured, `composer install` generates a single merged `bitbucket-pipelines.yml` containing all pipeline sections. Do not edit this file manually — changes will be overwritten on the next `composer install`.
### Acquia Review Apps
Acquia Review Apps create an [Acquia Cloud Development Environment (CDE)](https://docs.acquia.com/acquia-cloud-platform/manage-apps/dev-env/) for every pull request, equivalent to Pantheon Multidev environments.
To enable Acquia Review Apps on Bitbucket:
- Add the following to `composer.json`:
```json
"extra": {
"drainpipe": {
"bitbucket": ["AcquiaReviewApps"],
"acquia": { "settings": true }
}
}
```
- Run `composer install` to scaffold the following files into your project:
- `bitbucket-pipelines.yml` — generated at the repository root and kept up to date on every `composer install`. Do not edit this file manually — changes will be overwritten.
- `Taskfile.yml` — a `bitbucket` include pointing to `vendor/lullabot/drainpipe/tasks/bitbucket.yml` is auto-injected
**How it works**
When a pull request is opened or updated, the `pull-requests` pipeline:
1. Installs system dependencies and configures SSH
2. Runs `composer install`
3. Installs Acquia CLI and authenticates (`task bitbucket:acquia:setup`)
4. Runs the pre-deploy build hook if defined (`task bitbucket:acquia:build` → `task acquia:deploy:before`)
5. Pushes code to a PR-specific branch on Acquia, creates the CDE (`PR-{N}`) if it doesn't exist, copies the database from the source environment (default: `dev`) unless `ACQUIA_REVIEW_RUN_INSTALLER` is set, and waits for the code switch to complete (`task bitbucket:acquia:push-cde`)
6. Downloads Drush aliases, runs `task acquia:deploy:after` (if defined) and `task update` or `task drupal:update`, then posts the environment URL as a commit status (`task bitbucket:acquia:update-cde`)
Stale CDEs are **not** deleted automatically on PR close. See [Scheduling the cleanup pipeline](#scheduling-the-cleanup-pipeline) below.
**Bitbucket repository variables**
Add these in your Bitbucket repository settings under **Repository variables**:
| Variable | Secured | Description |
|---|---|---|
| `ACQUIA_API_KEY` | Yes | Acquia API Key |
| `ACQUIA_API_SECRET` | Yes | Acquia API Secret |
| `ACQUIA_SSH_PRIVATE_KEY` | Yes | SSH private key (base64-encoded) with Acquia Git access |
| `ACQUIA_APP_UUID` | No | Application UUID from the Acquia Cloud console |
| `ACQUIA_SITE_GROUP` | No | Application/site group name (e.g. `mysite` from `mysite.dev`) |
| `BITBUCKET_USERNAME` | No | Bitbucket username — required for commit status and cleanup API calls |
| `BITBUCKET_APP_PASSWORD` | Yes | Bitbucket App Password with `pullrequest:read` scope — required for commit status and cleanup |
| `ACQUIA_SOURCE_ENVIRONMENT` | No | Environment to copy the database from (default: `dev`) |
| `ACQUIA_REVIEW_RUN_INSTALLER` | No | Set to `"true"` to run `drush site:install --existing-config` instead of copying the database |
| `DRAINPIPE_PHP_EXTENSIONS` | No | Space-separated list of additional PHP extensions to install beyond those declared in `composer.json` (see [PHP extensions](#php-extensions)) |
> Note: `BITBUCKET_WORKSPACE`, `BITBUCKET_REPO_SLUG`, `BITBUCKET_COMMIT`, and `BITBUCKET_PR_ID` are injected automatically by Bitbucket Pipelines and do not need to be set manually.
**Scheduling the cleanup pipeline**
Bitbucket does not trigger pipelines on PR close. To avoid accumulating stale CDEs, schedule the `acquia-review-apps-cleanup` custom pipeline:
1. In your Bitbucket repository, go to **Repository settings → Pipelines → Schedules**
2. Add a new schedule for the `acquia-review-apps-cleanup` custom pipeline (e.g., daily at midnight)
**Known limitations**
- No automatic cancel-in-progress — multiple commits to the same PR will queue rather than cancel prior runs.
- Extra credentials required — `BITBUCKET_USERNAME` and `BITBUCKET_APP_PASSWORD` must be set manually, unlike GitHub where `GITHUB_TOKEN` is injected automatically.
## Tugboat
Add the following to `composer.json` to add Tugboat configuration:
```json
{
"extra": {
"drainpipe": {
"tugboat": {}
}
}
}
```
Then, run `ddev composer install` to generate:
- `.tugboat/config.yml` - Complete Tugboat configuration
- `.tugboat/scripts/` - Helper scripts (if needed)
- `web/sites/default/settings.tugboat.php` - Drupal settings for Tugboat
The following will be autodetected based on your `.ddev/config.yml`:
- Web server (nginx or apache)
- PHP version
- Database type and version
- Nodejs version
- Redis (Obtained with `ddev get ddev/ddev-redis`)
- Solr (Obtained with `ddev get ddev/ddev-solr`)
Additionally, Pantheon integration can be added:
```json
{
"extra": {
"drainpipe": {
"tugboat": {
"pantheon": true
}
}
}
}
```
This will install [Terminus](https://docs.pantheon.io/terminus) in the Tugboat environment. Add `TERMINUS_MACHINE_TOKEN` as a [Tugboat environment variable](https://docs.tugboatqa.com/setting-up-tugboat/select-repo-settings/#set-environment-variables) and set `PANTHEON_SITE_ID` in your `Taskfile.yml` vars. Then add a `sync:tugboat` task to fetch the database during Tugboat preview builds:
```
sync:tugboat:
desc: "Fetches a database from Pantheon and imports it in Tugboat"
vars:
DB_DIR: /var/lib/tugboat/files/db
cmds:
- task: pantheon:fetch-db
- task: drupal:import-db
```
Similarly, Acquia integration can be added:
```json
{
"extra": {
"drainpipe": {
"tugboat": {
"acquia": true
}
}
}
}
```
This will install [Acquia CLI (acli)](https://docs.acquia.com/acquia-cloud-platform/add-ons/acquia-cli/start) in the Tugboat environment. Add `ACQUIA_API_KEY` and `ACQUIA_API_SECRET` as [Tugboat environment variables](https://docs.tugboatqa.com/setting-up-tugboat/select-repo-settings/#set-environment-variables) and set `ACQUIA_ENVIRONMENT_ID` in your `Taskfile.yml` vars. Then add a `sync:tugboat` task:
```
sync:tugboat:
desc: "Fetches a database from Acquia and imports it in Tugboat"
vars:
DB_DIR: /var/lib/tugboat/files/db
cmds:
- task: acquia:fetch-db
- task: drupal:import-db
```
When using MySQL as the database engine in DDEV, Tugboat can be configured to
use the `percona` Docker image instead of `mysql`:
```json
{
"extra": {
"drainpipe": {
"tugboat": {
"percona": true
}
}
}
}
```
### Custom Templates
For the main `php` service, you can override any build phase template by copying
it to `.tugboat/drainpipe-templates/`. Example:
```
mkdir -p .tugboat/drainpipe-templates
cp vendor/lullabot/drainpipe/scaffold/tugboat/templates/php-init.yml.twig \
.tugboat/drainpipe-templates/
```
Edit `.tugboat/drainpipe-templates/php-init.yml.twig` to add, remove, or modify
commands, then regenerate the Tugboat configuration file with `ddev composer install`.
Available Templates:
- `php-init.yml.twig` - Init phase commands
- `php-update.yml.twig` - Update phase commands
- `php-build.yml.twig` - Build phase commands
- `php-online.yml.twig` - Online phase commands
- `config.yml.twig` - Complete Tugboat configuration (advanced)
### Tasks
Tugboat specific tasks are contained in [`tasks/tugboat.yml`](tasks/tugboat.yml).
Add the following to your `Taskfile.yml`'s `includes` section to use them:
```yml
includes:
tugboat: ./vendor/lullabot/drainpipe/tasks/tugboat.yml
```
| Task | Action | Usage |
|---|---|---|
| `task tugboat:drush-uli-ready` | Configures Drush with the Tugboat service URL for the environment. | Run it once as part of your Tugboat _build_ or _online_ commands defined at `.tugboat/config.yml`
It is assumed the following tasks exist:
- `sync`
- `build`
- `update`
- `online`
The `build`, `sync`, and `update` tasks can be overridden with `sync:tugboat`,
`build:tugboat`, and `update:tugboat` tasks if required (you will need to re-run
`composer install` to regenerate the Tugboat scripts if you are adding this
task to your `Taskfile.yml` for the first time).
```
sync:
desc: "Fetches a database from Pantheon and imports it"
cmds:
- task: pantheon:fetch-db
- task: drupal:import-db
sync:tugboat:
desc: "Fetches a database from Pantheon and imports it in Tugboat"
cmds:
- task: pantheon:fetch-db
vars:
DB_DIR: /var/lib/tugboat/files/db
- task: drupal:import-db
vars:
DB_DIR: /var/lib/tugboat/files/db
```
>>>
💡
`composer install` should be re-run if any changes are made to the DDEV
configuration.
>>>
#### Custom init commands
You can hook into the `init` step of any service by adding them to your
`Taskfile.yml`. These additional commands will be run at the end of the
init phase for the specific Tugboat service.
Supported services:
- Webserver: `tugboat:php:init`
- Database: `tugboat:mysql:init` / `tugboat:mariadb:init` / `tugboat:postgres:init`
- Memory cache: `tugboat:redis:init` / `tugboat:memcached:init`
Example:
```
tugboat:php:init:
cmds:
- apt-get install -y libldap2-dev
- docker-php-ext-install ldap
```
#### Custom online commands
You can also add an `online` step to the `php` service by adding a task
named `online:tugboat` and re-running `composer install`.
### Additional Tugboat keys
Drainpipe will fully manage your `.tugboat/config.yml` file, you should not edit
it. The following keys can be added to your `config.yml` via a
`.tugboat/config.drainpipe-override.yml` file:
```
php:
aliases:
urls:
screenshot:
visualdiff:
solr:
commands:
checkout:
depends:
volumes:
environment:
aliases:
urls:
```
### Mail Configuration
By default, Drainpipe configures Tugboat environments to capture email using Tugboat's built-in mail capture service. This automatically configures:
- The core mail system to use `php_mail`
- The Mail System module (if installed) to use `php_mail` as the sender
- Symfony Mailer (if installed) to send mail through Tugboat's SMTP service
If you need to use a different mail configuration (e.g., for testing with a specific mail service or module), you can override these settings in your custom settings file (typically `web/sites/default/settings.tugboat.php` or `web/sites/default/settings.php`).
For example, to use a different mail backend:
```php
// Override the default Drainpipe mail configuration.
// This should come after including settings.tugboat.php
if (getenv('TUGBOAT_REPO')) {
// Example: Use a custom mail transport
$config['system.mail']['interface']['default'] = 'my_custom_mailer';
// Example: Configure Symfony Mailer differently
$config['symfony_mailer.settings']['default_transport'] = 'custom_transport';
$config['symfony_mailer.mailer_transport.custom_transport']['plugin'] = 'smtp';
$config['symfony_mailer.mailer_transport.custom_transport']['configuration']['host'] = 'custom.smtp.example.com';
$config['symfony_mailer.mailer_transport.custom_transport']['configuration']['port'] = '587';
}
```
## Contributor Docs
This repo is public.
Please be careful to remove sensitive customer specifics when posting Issues or comments.
First time contributors need a maintainers approval for automated tests to run.
(This is so we aren't at risk of getting a big CI bill accidentally, or maliciously.)
Peer Reviewing by looking at PR code changes is nice.
Testing PR code changes on real sites is extra beneficial.
### Local Development
In order to test local changes follow the instructions for the [test script](./docs/test-script.md).
### Peer Review Guidelines for Automated Updates
These are guidelines for conducting peer reviews on automated dependency update pull requests created by Renovate.
All automated updates submitted by Renovate undergo a series of automated tests via GitHub Actions. These tests are designed to ensure compatibility and stability with the new versions of dependencies.
All Renovate peer reviews regardless if they're a minor or patch release require:
1. Reading the change logs carefully to understand the new features and fixes.
- Assess if the changes necessitate additional test coverage or could potentially impact existing functionality.
- Consider the implications of new features on the project's future development and maintenance.
2. All tests and checks must pass
#### Handling Version Ranges
Some dependencies allow multiple versions, like `"drush/drush": "^10|^11|^12"`.
- Renovate will create pull requests when any of these versions get patch or minor releases.
- We **DO NOT** want to merge these, because it would pin these packages to a specific version.
- We **DO** want to allow these pull requests to run checks. This will confirm that the latest version within the range Drainpipe supports is unlikely break builds.
- After all GitHub Action checks pass, leave a comment on the pull request stating such, close the pull request, and delete the branch.
#### Handling Test Failures
Occasionally, tests may fail due to transient issues or flakiness in the test suite. In such cases:
1. Verify the nature of the test failure to ensure it's not related to the dependency update.
2. If the failure seems unrelated to the update, re-run the GitHub Actions job to confirm if the issue persists.
3. Document any recurring flakiness or issues on the pull request then create a new issue linked to the pull request for further investigation.
### Conducting the Peer Review
1. **Review the Automated Update Pull Request (PR)**:
- Ensure the PR title and description clearly describe the update and its scope.
- Check the list of changed files to understand the extent of the update.
2. **Assess Test Results**:
- Ensure all GitHub Actions tests have passed. Pay close attention to tests that touch on updated dependencies.
- For failed tests, follow the "Handling Test Failures" guidelines above.
3. **Read the Dependency Change Logs**:
- For minor point releases, review the dependency's change logs to identify any significant changes or additions.
- Evaluate how these changes might affect the Drainpipe project.
5. **Final Decision**:
- For patch releases with all tests passing, proceed to merge the update.
- For minor point releases, after thorough review and consideration, decide whether to merge the update or request manual testing before merging.
### Releases
#### drainpipe and drainpipe-dev release process
When making a release, increase the version based on https://semver.org/
> MAJOR version when you make incompatible API changes
> MINOR version when you add functionality in a backward compatible manner
> PATCH version when you make backward compatible bug fixes
Specifically for drainpipe, when a new "check" is added, that might break builds in projects,
that would usually be a MINOR release, with a release note about the change.
Before making a new release, post in the lullabot internal #devops slack channel to coordinate with other maintainers.
1. Generate a GitHub release for drainpipe
1. Supply the correct tag based on the changes and semantic versioning standards.
2. Use the _Generate release notes_ button and review the changes to confirm the new version is correct based on semantic versioning.
3. Set this release as latest and publish.
2. The release when published will automatically kick off a release of [drainpipe-dev](https://github.com/Lullabot/drainpipe) using the [DrainpipeDev GitHub workflow](https://github.com/Lullabot/drainpipe/actions/workflows/DrainpipeDev.ym).
3. Visit the [project board](https://github.com/orgs/Lullabot/projects/12/views/1) and archive the _Ready to Release_ column.
#### NPM package release process
To generate new NPM package releases:
1. Have the latest main branch checked out locally
2. Run `yarn install && yarn lerna publish`
3. Create a pull request with the changes
4. Once merged, locally switch to the main branch and run `yarn lerna exec -- npm publish`