PHPackages                             fourkitchens/pots - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [DevOps &amp; Deployment](/categories/devops)
4. /
5. fourkitchens/pots

ActiveLibrary[DevOps &amp; Deployment](/categories/devops)

fourkitchens/pots
=================

Push On To Site. Scripts to help aid in deployment for Drupal sites.

0.6.0(3w ago)218.0k↓15.9%3[26 issues](https://github.com/fourkitchens/pots/issues)[3 PRs](https://github.com/fourkitchens/pots/pulls)GPL-3.0-or-laterShell

Since Sep 3Pushed 1mo ago11 watchersCompare

[ Source](https://github.com/fourkitchens/pots)[ Packagist](https://packagist.org/packages/fourkitchens/pots)[ RSS](/packages/fourkitchens-pots/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (5)DependenciesVersions (38)Used By (0)

Circle CI Starter for Projects
==============================

[](#circle-ci-starter-for-projects)

This Composer package provides the starts for what you need to test and deploy a hosted site on something like Acquia, Pantheon, or elsewhere.

What does POTS stand for?
-------------------------

[](#what-does-pots-stand-for)

Whatever you want it to stand for. Here's some options:

- Push On To Site
- Party On That Site
- Perform On The Server
- People Overlook This Stuff
- ProjectCI Onward To Standardization

TOC
---

[](#toc)

- [Upgrading](#upgrading)
- [Dependencies](#dependencies)
- [Installation](#installation)
- [Configure Environment](#configure-environment)
    - [Shared](#shared)
        - [Deploy Bot Setup](#deploy-bot-setup)
            - [Create a GitHub Account for the Deploy Bot](#create-a-github-account-for-the-deploy-bot)
        - [Configure an SSH Key](#configure-an-ssh-key)
        - [Get a Github Token](#get-a-github-token)
        - [Configure Environment Variables](#configure-environment-variables)
    - [Pantheon](#pantheon)
        - [Create a Pantheon Account for your Deploy Bot](#create-a-pantheon-account-for-your-deploy-bot)
        - [Set up SSH Key](#set-up-ssh-key)
        - [Get a Terminus Token (or Machine Token)](#get-a-terminus-token-or-machine-token)
        - [Configure More CircleCi Environment Variables](#configure-more-circleci-environment-variables)
    - [Acquia](#acquia)
        - [Create an Acquia Account for your Deploy Bot](#create-an-acquia-account-for-your-deploy-bot)
        - [Set up SSH Key](#set-up-ssh-key-1)
        - [Configure More CircleCi Environment Variables](#configure-more-circleci-environment-variables-1)
- [Configure CircleCI config.yml](#configure-circleci-configyml)
    - [Pipeline Parameter Defaults](#pipeline-parameter-defaults)
        - [run-playwright-e2e-tests](#run-playwright-e2e-tests)
        - [Visual regression tests (label-triggered)](#visual-regression-tests-label-triggered)
        - [playwright-vrt-target-env](#playwright-vrt-target-env)
        - [playwright-path](#playwright-path)
        - [php-version](#php-version)
        - [tz](#tz)
        - [host-variant](#host-variant)
            - [pantheon](#pantheon)
            - [acquia](#acquia)
            - [general](#general)
        - [docroot](#docroot)
        - [artifact\_workspace](#artifact_workspace)
    - [Other Configuration](#other-configuration)
        - [persisting\_dirs](#persisting_dirs)
        - [Playwright Jobs](#playwright-jobs)
- [Configurable Environment Variables](#configurable-environment-variables)
    - [Shared](#shared-1)
    - [Pantheon Specific](#pantheon-specific)
    - [Acquia Specific](#acquia-specific)
- [Helper Environment Variables](#helper-environment-variables)
- [Configure Composer.json](#configure-composerjson)
- [Configure Scripts](#configure-scripts)
    - [Pantheon Specific Scripts](#pantheon-specific-scripts)
- [Automatic security Updates](#automatic-security-updates)
    - [Steps to set the keys](#steps-to-set-the-keys)
    - [Steps to set IA key](#steps-to-set-ia-key)

Upgrading
---------

[](#upgrading)

If you are using the standard scripts that ship with this package, upgrading should be easier. With each version upgrade, you should check your `.circleci/config.yml` file for changes against the `config.yml` file here.

The easiest way to do this is to use a standardized diff tool and diff `.circleci/config.yml` with `config.yml`. An example may look like:

```
diff -u --color .circleci/config.yml ./vendor/fourkitchens/pots/config.yml

```

Validate the changes and move over the ones you want to keep.

### Migrating off the `build-tools-ci` image

[](#migrating-off-the-build-tools-ci-image)

Pantheon deprecated the `quay.io/pantheon-public/build-tools-ci` Docker image family in June 2026. If your `.circleci/config.yml` still pins that image on any Pantheon job (`deploy_to_pantheon*`, `security_updates_check`) or the Playwright jobs, replace those `docker.image` entries with `cimg/php:>` (Playwright jobs use the `playwright-executor`) and add the `install-terminus` step to each job that uses Terminus, exactly as shipped in the current `config.yml`. Terminus is now installed at runtime and pinned via the new `terminus-version` and `terminus-build-tools-version`parameters — set those if you need versions other than the defaults.

Dependencies
------------

[](#dependencies)

This package expects your project to have the following support scaffolding to run out of the box:

- the composer scripts lint and code-sniff. Example: ```
     "scripts": {
        "lint": [
           "./node_modules/.bin/eslint ./",
           "find web/modules/custom web/themes/custom \\( -iname  '*.php' -o -iname '*.inc' -o -iname '*.module' -o -iname '*.install'-o -iname '*.theme' \\) '!' -path '*/node_modules/*' -print0 | xargs -0 -n1 -P8 php -l"
        ],
        "code-sniff": [
           "./vendor/bin/phpcs"
        ]
     }

    ```
- package.json with a build-theme script. Example: ```
       "scripts": {
          "theme-build": "cd ./docroot/themes/custom/sdsu && npm run build"
       }

    ```
- package.lock or shrinkwrap.
- preferably a .nvmrc
- .gitignore files with cut lines in them to distinguish source from artifact. Here's an example [.gitignore](https://github.com/pantheon-systems/example-drops-8-composer/blob/master/.gitignore).

Set up of the Circle tasks assumes you are doing this with a bot user. Please ensure that the bot user you are using has account on both the GitHub organization where your site lives and the hosting provider. You will need:

- the ability to log in as the bot user in GitHub and on the hosting provider
- an SSH Key (private and public)
- an api or machine token for the hosting tooling such as terminus or acli

Installation
------------

[](#installation)

1. Install the package and copy over the template config.yml

    ```
    composer require fourkitchens/pots
    mkdir .circleci
    cp vendor/fourkitchens/pots/config.yml .circleci/config.yml

    ```
2. Make sure your composer.json and package.json meet the requirements of the default scripts.
3. Push the changes to a public GitHub branch.
4. Log in to
5. Navigate to the organization that your site's code lives under by clicking the icon in the top left corner where your name is and selecting the correct one.
6. Navigate to Projects
7. Find the Repo name for your site
8. Click the "Set Up Project" button next to it
9. Choose Fastest
10. Type in the branch you pushed your changes up to where the "git branch" icon is in the dialog.
11. Verify the wrench icon turns Green and lets you know it found a config.json
12. Click "Set Up Project"

The first pass will always fail. Move on to configuration.

Configure Environment
---------------------

[](#configure-environment)

There are some configuration steps that are shared between hosting environments. Make sure to check out the settings specific to the environment you are pushing to.

### Shared

[](#shared)

#### Deploy Bot Setup

[](#deploy-bot-setup)

A Deploy Bot user will be needed. This tooling assumes Bender (the Four Kitchens deploy bot) as the default, but does not provide any credentials you need to set the tooling up. Ask a Web Chef about Bender, have the organization you are working with create a new bot, or create the new bot for them using the steps below. You will need to log in as this bot to do some of the configuration.

##### Create a GitHub Account for the Deploy Bot

[](#create-a-github-account-for-the-deploy-bot)

1. Open a new browser instance or log out of your current GitHub instance.
2. Go to .
3. Type a username, your email address, and a password. NOTE: Make sure the email address you enter goes to a real email account. If you use gmail, it is possible to have multiple "addresses" go to the same account using the `+` in your email. See how to [create task-specific email addresses](https://support.google.com/a/users/answer/9308648?hl=en)
4. Choose Sign up for GitHub, and then follow the instructions.
5. Securely provide the credentials to the client.
6. In a new browser instance, as an administrator of the organization that owns the site, [invite the bot user to the organization](https://docs.github.com/en/organizations/managing-membership-in-your-organization/inviting-users-to-join-your-organization#inviting-a-user-to-join-your-organization).

#### Configure an SSH Key

[](#configure-an-ssh-key)

An SSH key is needed to be able to push commits from circleci to the hosting provider's git repository. In some instances, the same ssh key is also needed to be able to ssh into the hosting platform itself. Ask the client to generate an ssh key pair or [generate](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key)and securely provide the ssh key pair to the client.

1. Log in to
2. Navigate to the organization that your site's code lives under by clicking the icon in the top left corner where your name is and selecting the correct one.
3. Navigate to Projects
4. Find the Repo name for your site and click it.
5. Validate you see failed workflows.
6. Click on "Project Settings"
7. Click on "SSH Keys"
8. Navigate to "Additional SSH Keys"
9. Click "Add SSH Key"
10. Copy the contents of the private SSH Key you were provided (or generated) for the bot user into the Private Key field in the dialog that appears.
11. Verify that you have no extraneous spaces or newlines.
12. Click "Add SSH Key" to close the dialog and accept the changes.
13. Note the fingerprint for future use. **Note:** you can check to make sure the file was copied correctly by validating that the fingerprint in circleci is the same as what is displayed by the command `ssh-keygen -l -E md5 -f id_rsa` where idrsa is the filename of your key.

#### Get a Github Token

[](#get-a-github-token)

You must have a GitHub token so the Deploy Bot can post comments back to commits or pull requests. This allows it to provide links and information about the environments it created.

If you skipped here, make sure you follow steps 1-6 of "Configure an SSH Key" to get to Circle's Project Settings"

1. In a new browser instance, log in to GitHub as the Deploy Bot.
2. Follow the instructions for [creating a personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token#creating-a-token)
3. Choose the complete repo access option.
4. Save the access token securely, so you will have access to it. It will only be displayed once.

#### Configure Environment Variables

[](#configure-environment-variables)

Here you will configure the common environment variables. Hosting specific variables and steps will be provided farther down. The variables to configure are as follows.

- `GITHUB_TOKEN` A GitHub access token so the bot user can comment back on the commit.
- `GIT_EMAIL` An arbitrary email that will be used as the committer when building the artifact.
- `CANONICAL_ENV` The environment to get canonical database and files from.

If you skipped here, make sure you follow steps 1-6 of "Configure an SSH Key" to get to Circle's Project Settings"

1. Switch back to your browser instance where you are logged into CircleCI -&gt; Project Settings
2. Click "Environment Variables" on the left hand side.
3. Click "Add Environment Variable"
4. Type "GITHUB\_TOKEN" in the name
5. Copy the token value into "Value"
6. Click "Add Environment Variable" to accept the changes.
7. Click "Add Environment Variable"
8. Type "GIT\_EMAIL" in the name
9. Type the email address associated with the Deploy Bot into "Value"
10. Click "Add Environment Variable" to accept the changes.

### Pantheon

[](#pantheon)

- `SITE_NAME`: The Pantheon site id used to run terminus commands.
- `TERMINUS_TOKEN`: The Pantheon Machine Token used to operate terminus.

#### Create a Pantheon Account for your Deploy Bot

[](#create-a-pantheon-account-for-your-deploy-bot)

For Pantheon hosted sites, we need an account for our Deploy Bot so that our deployments are linked to any one pantheon user.

1. Log in as an administrator of your Pantheon Organization.
2. Click your user's name in the top right corner of the dashboard
3. Navigate down to the organization name you want to create a user for.
4. Click the "People" tab.
5. Click the "Add User" button.
6. Select "Team Member" for Role.
7. Add the same email address you created the GitHub account for previously.
8. Click "Add User".
9. In a new browser instance, check the email that's associated with that user.
10. Accept the invitation.

#### Set up SSH Key

[](#set-up-ssh-key)

Your bot will need an ssh key configured to be able to push commits to Pantheon. Use the public key of the pair generated in the "Configure an SSH Key" section.

Log out of your Pantheon account or use a separate browser instance to follow the instructions from Pantheon to [Add Your SSH Key to Pantheon](https://pantheon.io/docs/ssh-keys#add-your-ssh-key-to-pantheon).

#### Get a Terminus Token (or Machine Token)

[](#get-a-terminus-token-or-machine-token)

1. In the same browser instance as above, follow the instructions from Pantheon to [Create a Machine Token](https://pantheon.io/docs/machine-tokens#create-a-machine-token)
2. Save the machine token securely, so you will have access to it. It will only be displayed once.

#### Configure More CircleCi Environment Variables

[](#configure-more-circleci-environment-variables)

1. Navigate back to your CircleCI -&gt; Project Settings -&gt; Environment Variables browser instance.
2. Click "Add Environment Variable"
3. Type "SITE\_NAME" in the name
4. Type the site id (or `TERMINUS SITE ID`) of your Pantheon site into "Value". **Note:** you can find the site id by looking at the site's dashboard in Pantheon. If you click the "Visit Site" button on any environment the url is in the format of `https://{{TERMINUS ENV}}-{{TERMINUS SITE}}.pantheonsite.io/`
5. Click "Add Environment Variable" to accept the changes.
6. Click "Add Environment Variable".
7. Type "TERMINUS\_TOKEN" in the name.
8. Copy the machine token value you saved earlier into "Value".
9. Click "Add Environment Variable" to accept the changes.

### Acquia

[](#acquia)

- `SITE_NAME`: The acquia site id used to run Acquia Cloud API commands.
- `ACQUIA_REALM`: The Cloud API Realm. Usually "prod" or "devcloud".
- `ACQUIA_REPO`: The Acquia git repo.

#### Create an Acquia Account for your Deploy Bot

[](#create-an-acquia-account-for-your-deploy-bot)

**TODO: FILL OUT THIS BIT**

#### Set up SSH Key

[](#set-up-ssh-key-1)

Your bot will need an ssh key configured to be able to push commits to Acquia. Use the public key of the pair generated in the "Configure an SSH Key" section.

Log out of your Acquia account or use a separate browser instance to follow the instructions from Acquia to [Add a public key to an Acquia profile](https://docs.acquia.com/cloud-platform/manage/ssh/enable/add-key/).

#### Configure More CircleCi Environment Variables

[](#configure-more-circleci-environment-variables-1)

1. Navigate back to your CircleCI -&gt; Project Settings -&gt; Environment Variables browser instance.
2. Click "Add Environment Variable".
3. Type "ACQUIA\_REPO" in the name.
4. Type the Acquia repo url into "Value". **TODO:** FLESH THIS OUT MORE WITH HELP ON HOW TO GET IT
5. Click "Add Environment Variable" to accept the changes.
6. Click "Add Environment Variable".
7. Type "ACQUIA\_REALM" in the name.
8. Type the Acquia Realm id into "Value". **TODO:** FLESH THIS OUT MORE WITH HELP ON HOW TO GET IT
9. Click "Add Environment Variable" to accept the changes.
10. Click "Add Environment Variable".
11. Type "SITE\_NAME" in the name.
12. Copy the Acquia site id into "Value". **TODO:** FLESH THIS OUT MORE WITH HELP ON HOW TO GET IT
13. Click "Add Environment Variable" to accept the changes.
14. Click "Add Environment Variable".
15. Type "CU\_TOKEN" in the name.
16. Paste your ClickUp API token into "Value" (stored in 1Password). This is the only ClickUp secret; the rest of the ClickUp settings travel in the `click-data` pipeline parameter — see [Automatic Security Updates](#automatic-security-updates) below.
17. Click "Add Environment Variable" to accept the changes.

Configure CircleCI config.yml
-----------------------------

[](#configure-circleci-configyml)

There are many options you have, some shared, and some hosting specific.

### Pipeline Parameter Defaults

[](#pipeline-parameter-defaults)

Currently, you can configure your entire script by setting up some pipeline parameter defaults. These can be changed via API calls (advanced usage), but the defaults will be used when you are making pull requests or commits directly to the repository that houses your .circleci/config.yml.

In each one, change the value after the `default:` key. For example, to change the docroot across the whole project, change:

```
  docroot:
    description: "Where composer installs drupal."
    default: "web"
    type: string

```

to

```
  docroot:
    description: "Where composer installs drupal."
    default: "docroot" #NOTE I CHANGED THIS
    type: string

```

The following parameters exist:

#### run-playwright-e2e-tests

[](#run-playwright-e2e-tests)

This boolean controls whether the Playwright end-to-end test job runs after the Pantheon multidev is created.

Default: `true`

When enabled, the `playwright-e2e-test` job will:

- restore the built project from the artifact workspace
- install dependencies from the Playwright test directory
- install Playwright browsers
- wake the Pantheon environment
- run `npx playwright test --grep-invert "@vrt"`

Use this when you want standard browser coverage on the deployed multidev but you do not want visual regression tests mixed into that run.

#### Visual regression tests (label-triggered)

[](#visual-regression-tests-label-triggered)

VRT is no longer controlled by a parameter or a manual approval. It runs when a pull request is labeled — **`run vrt tests`** (VRT only) or **`run vrt tests with fresh db`** (refresh DB + files from live, then VRT). See [Visual regression testing](#visual-regression-testing) below for the trigger prerequisites and behavior.

#### playwright-vrt-target-env

[](#playwright-vrt-target-env)

This string defines which Pantheon environment should be used as the visual baseline for VRT comparisons.

Default: `"live"`

During the `playwright-vrt-test` job, this value is exported as `VRT_TARGET_ENV`. The currently deployed multidev becomes the source environment, and the target environment becomes the baseline for comparison.

#### playwright-path

[](#playwright-path)

This string points to the directory that contains your Playwright project.

Default: `"test/playwright"`

This directory is expected to contain the files needed for Playwright CI runs, including `package.json` and your Playwright configuration. The current jobs use this path for:

- `npm ci`
- `npx playwright install --with-deps`
- `npx playwright test --grep-invert "@vrt"`
- `npm run vrt:ci`

If your tests live somewhere else, update this parameter instead of changing each job manually.

#### php-version

[](#php-version)

This is a string that represents the version number for PHP version to use across the entire build.

This value must be a valid `cimg/php` tag. Both major.minor (e.g. `"8.4"`) and major.minor.patch (e.g. `"8.4.2"`) are supported.

#### terminus-version

[](#terminus-version)

This is a string controlling the [Terminus](https://github.com/pantheon-systems/terminus)version installed at runtime by the `install-terminus` command. Because Pantheon jobs now run on a standard image instead of the deprecated `build-tools-ci` container, Terminus is installed during the build rather than baked into the image.

Provide a full Terminus version to pin (e.g. `"4.3.2"`, the default). Pinning keeps builds reproducible and prevents a bad upstream release from breaking every project at once. The Build Tools and Secrets plugins are installed at their latest versions compatible with the installed Terminus, so there is no separate version parameter for them.

#### tz

[](#tz)

This is a string that represents the timezone. This may be important so that jobs that do time calculations, print time stamps, or make commits are accurate. See a [full list of timezone values](https://vdc-repo.vmware.com/vmwb-repository/dcr-public/3d076a12-29a2-4d17-9269-cb8150b5a37f/8b5969e2-1a66-4425-af17-feff6d6f705d/doc/timezone.html)to find an appropriate one for you to use.

#### host-variant

[](#host-variant)

This affects how the whole build behaves and what configurations are available to you. The current options are "pantheon", "acquia", and "general". All our workflows will provide you with "Artifact Build", committed the appropriate repository. This allows you to use Git history to follow a build back to the source commit we use in development.

##### pantheon

[](#pantheon-1)

Pantheon provides you a workflow that builds multidev environments, options around development branches, and a workflow to deploy code via approval through the CircleCI user interface. The deploy process provided by this setting creates an Artifact Build using Pantheon's [Terminus](https://github.com/pantheon-systems/terminus)with the aid of the [Build Tools](https://github.com/pantheon-systems/terminus-build-tools-plugin)plugin. These changes are committed only to the Pantheon git repository and not to your "Source Repository", the one you create coding changes in.

Pantheon jobs run on the standard `cimg/php` image and install Terminus (and, for the dev/multidev deploy, the Build Tools plugin) at runtime via the `install-terminus`command. This replaces the deprecated `quay.io/pantheon-public/build-tools-ci`container, which [Pantheon stopped maintaining in June 2026](https://docs.pantheon.io/release-notes/2026/06/build-tools-ci-deprecated). The Build Tools plugin itself is not deprecated and is still used. The Terminus version is controlled by the `terminus-version` parameter described above; its plugins install at their latest compatible versions.

##### acquia

[](#acquia-1)

Acquia provides you a very minimal workflow, however, it does provide [acquia cli](https://github.com/acquia/cli) as part of the build. This allows you to use supporting deploy methods like our [cloud hooks](https://github.com/fourkitchens/acquia-cloud-hooks)to streamline the deployment process. For multidev capabilities, it is recommended to use [tugboat](https://www.tugboatqa.com/). The deploy process provided by these settings creates an Artifact Build using some standard git commands. These changes are committed only to the Acquia git repository and not to your "Source Repository", the one you create coding changes in.

##### general

[](#general)

General provides you with the barest of deployments, committing an artifact build back to your source repository under a new branch that follows the naming convention `deploy-{BRANCHNAME}`. Example, if your branch is named `test`, you will have an artifact build committed to the `deploy-test` branch.

#### docroot

[](#docroot)

This setting should be set to the folder where your Drupal installation resides. This should mirror the setting in `extra.drupal-scaffold.locations.web-root`. This is typically either `web` for Pantheon and `docroot` for Acquia, but can be any number of things like `public_html` for generic hosts.

#### artifact\_workspace

[](#artifact_workspace)

This setting moves where the built artifact should be. This is particularly helpful when you want to pick and choose items from the build versus just sending the whole artifact to your host. The `~/project` directory is always committed to an "Artifact Build". Therefore, by changing this directory to something like `/tmp/project`, you can use rsync to move parts built by the previous build script into `~/project`. By default, this value of this setting is `~/project`, so that everything that was built during the "build" job is then pushed to the host.

### Other Configuration

[](#other-configuration)

There are other configuration that cannot be affected by API calls and requires you to modify your config.yml directly if you wish to change them temporally or permanently.

#### persisting\_dirs

[](#persisting_dirs)

There are the directories that you want to be copied in full from the build portion of the workflow to the deploy portion of the workflow. You will sometimes want to include other root directories that aren't included like `node_modules`, `simplesaml`, or `private`. We exclude most top level directories because they are unneeded on the hosting system itself.

#### Playwright Jobs

[](#playwright-jobs)

The Playwright jobs are currently part of the Pantheon workflow only. Their purpose is to validate the freshly deployed multidev before any later manual deployment steps.

The workflow order is:

- `deploy_to_pantheon` deploys the multidev
- `playwright-e2e-test` runs automatically after that deploy (when `run-playwright-e2e-tests` is enabled)

VRT runs in a separate, label-triggered workflow (see below), not inside `build-deploy-pantheon`.

Some practical details:

- The E2E job excludes any test tagged with `@vrt`
- The VRT job expects an `npm run vrt:ci` script in your Playwright project
- Both jobs store the Playwright HTML report as a CircleCI artifact

### Visual regression testing

[](#visual-regression-testing)

VRT is triggered on demand by labeling a pull request. There are two labels:

- **`run vrt tests`** → the `vrt-on-label` workflow runs VRT against the PR's already-deployed multidev (the one `build-deploy-pantheon` created on push). It does not redeploy; the `build` job only produces the workspace and dependencies the VRT jobs need.
- **`run vrt tests with fresh db`** → the `vrt-on-label-fresh-db` workflow first runs `vrt_sync_from_live`, which clones the **database and files** from the canonical/live environment into the multidev and runs the deploy commands (`drush-commands`, including `deploy:hook`), then runs VRT. Use this when the visual diff should reflect the branch's code applied on top of live content. (The sync refuses to run against `dev`/`test`/`live` as a safety guard.)

Under the hood, each VRT workflow is gated on the `vrt-mode` pipeline parameter (`plain` / `fresh-db`); a normal push/PR pipeline leaves it at the default `none`and runs the usual `build-deploy-pantheon` workflow only. CircleCI's native label triggers can't match arbitrary label names, so the labels are wired up through a small GitHub Actions workflow that calls the CircleCI API.

**Prerequisite — one-time project setup:**

1. **Copy the trigger workflow** `templates/github-workflows/vrt-label-trigger.yml`from this package into your repository's `.github/workflows/` directory.
2. **Add a CircleCI API token** as the repository Actions secret **`CIRCLECI_TOKEN`**(a machine/bot user's personal API token is recommended). The Action uses it to trigger the pipeline via `POST /api/v2/project/gh///pipeline`.
3. **Create the two labels** on the repo: `run vrt tests` and `run vrt tests with fresh db`.

When you label a PR, the Action maps the label to `vrt-mode` (`plain` or `fresh-db`) and starts a CircleCI pipeline on the PR's head branch. Only the matching VRT workflow runs — it does not start another `build-deploy-pantheon`. (Fork PRs are not supported: GitHub withholds secrets from forked-PR Action runs and the head branch isn't in the base repo.)

To run VRT: push your branch (the normal pipeline builds and deploys the `pr-` multidev), then add either label to the PR. Remove and re-add the label to run it again. Use `playwright-vrt-target-env` to choose the baseline environment for the comparison.

> Note: `drush deploy:hook` now runs as part of the standard deploy commands (`scripts/pantheon/drush-commands`) on every Pantheon deploy, not just VRT.

This makes the default flow easier to manage: regular browser coverage can run automatically, while the slower visual comparison step stays opt-in.

Configurable Environment Variables
----------------------------------

[](#configurable-environment-variables)

Environment variables can be configured using the CircleCI Environment Variables interface, or you can set them directly in `.circleci/config.yml`. Changing them in the interface makes upgrading your `.circleci/config.yml` less problematic, however, it hides some of the toggles you may be using. Per best practices, make sure any secret is configured in the CircleCI UI. We also include all mandatory environment variables in this way as well.

### Shared

[](#shared-1)

- `GITHUB_TOKEN`: **Mandatory** A GitHub access token so the bot user can comment back on the commit or PR, and remove unneeded multidevs.
- `SITE_NAME`: The Pantheon or Acquia site id used to run terminus/acli commands. Defaults to the GitHub repo name.
- `GIT_EMAIL`: An arbitrary email that will be used as the committer when building the artifact. Defaults to `bender@fourkitchens.com`
- `CANONICAL_ENV`: Environment to get canonical database and files from Possible Values:

    - Acquia: dev, test, prod
    - Pantheon: dev, test, live

    Default: "prod" on Acquia. "live" on Pantheon
- `SANITIZE_SCRIPT`: Script used to sanitize databases. Only used when `CANONICAL_ENV` is not dev. There is no default.
- `SYNC_CONFIG`: The ability to turn configuration sync on or off. By default, Yes if Any directory in the ./config directory (inclusive) contains `system.site.yml`. Ex: YES if `./config/system.site.yml` or `./config/default/system.site.yml` or `./config/sync/system.site.yml`exists. Possible values are `YES`, or `NO`.
- `BASIC_USER`: Optional username used when the deployed Pantheon environment is protected by HTTP basic authentication. If set together with `BASIC_PASS`, the Playwright E2E job will use those credentials when waking the site over HTTP.
- `BASIC_PASS`: Optional password paired with `BASIC_USER` for HTTP basic authentication during Playwright E2E runs.

### Pantheon Specific

[](#pantheon-specific)

- `TERMINUS_TOKEN`: **Mandatory** The Pantheon machine token.
- `CI_BUILD`: Build CI multidevs on every commit on Pantheon. This way you get the ci-\* environments. This may be useful for visual regression testing or workflows without PRs. Defaults to `NO`. Possible values are `YES` and `NO`.
- `MAIN_BRANCH`: Define the main branch releases are cut from. Defaults to `main` if the branch exists, `master` otherwise.
- `DEVELOPMENT_BRANCH`: Define the development branch where active development happens on GitHub. This branch is used most in gitflow development patterns. Defaults to `develop`.
- `REBUILD_MULTIDEV_ENV_EVERY_PUSH`: Re-sync content for multidevs every time a push is made to Pantheon. Defaults to `NO`. Possible values are `YES` and `NO`.
- `REBUILD_DEVELOPMENT_ENV_EVERY_PUSH`: Re-sync content for the GitHub development multidev on Pantheon every time a push is made to `DEVELOPMENT_BRANCH` branch. Defaults to `NO`. Possible values are `YES` and `NO`.
- `DEVELOPMENT_ENV`: Define the name of the multidev used for the GitHub development branch. Must follow the multidev naming conventions for Pantheon. Defaults to `github-dev`.

### Acquia Specific

[](#acquia-specific)

- `ACQUIA_REPO`: **Mandatory** The address of the Acquia git repo. Example: `sitename@svn-21939.prod.hosting.acquia.com:sitename.git`.
- `ACQUIA_REALM`: **Mandatory** The Acquia Cloud API Realm. Usually "prod" or "devcloud". See [documentation](https://docs.acquia.com/acquia-cloud/api#realm). Defaults to `prod`.

Helper Environment Variables
----------------------------

[](#helper-environment-variables)

These environment variables are unconfigurable. They are set to help you with developing scripts on your own. Some contain the values of the pipeline parameters previously mentioned.

- `HOST_VARIANT`: Contains the value provided by the host-variant pipeline parameter.
- `DATE_TIMEZONE`: Contains the value provided by the tz pipeline parameter.
- `DOCROOT`: Contains the value provided by the docroot pipeline parameter.
- `TERM`: "xterm"

Configure Composer.json
-----------------------

[](#configure-composerjson)

There are 2 scripts that the default scripts require you to build so that it's reusable across the project. You must be able to run the following commands in your project.

```
composer run lint
composer run code-sniff

```

See the [Dependencies](https://github.com/fourkitchens/pots#dependencies) section for examples.

Configure Scripts
-----------------

[](#configure-scripts)

Almost all actions provided by this framework are overloadable. By simply providing a script in the correct location in `.circleci/scripts`, you can make this tooling do what ever steps you want to. We provide a default set of actions in the scripts section of this repository which you can use to base your custom scripts off of.

The scripts available for overload are as follows:

- `test/static`: Provides static code testing such as linting and code standards validation. By default, this runs `composer run lint; composer run code-sniff`
- `build/php`: Provides functionality to build your application. By default, this is simply optimizing a production ready dependency install.
- `build/theme`: Provides functionality to build your custom themes. By default, this runs `npm run theme-build` and runs through `$DOCROOT/themes/custom` and performs a "cut" action on each .gitignore, so you can provide both a list of items that should be ignored while coding and a list that's ignored when building your artifact.
- `deploy`: All the actions needed to push the Artifact build to the remote hosting environment. On Pantheon, this includes creating and building the multidev. On Acquia and General hosting, this just gets the Artifact code to the repo it should live in.

For Playwright support, your project should also provide a Playwright workspace at the path configured by `playwright-path`. In practice that means:

- a `package.json` that supports `npm ci`
- standard E2E tests that can run with `npx playwright test --grep-invert "@vrt"`
- a VRT script named `vrt:ci` for the visual regression job

If you want a spec to run only as part of VRT, tag it with `@vrt` so it is excluded from the standard E2E job.

### Pantheon Specific Scripts

[](#pantheon-specific-scripts)

- `drush-commands`: Provides the basic deployment drush commands to run update hooks, clear the cache, and sync configuration.
- `drush-config-import`: Provides the commands for importing configuration. By default, this provides drupal 8+ ready commands like `drush cim`, but can be swapped out for something like `drush fra` if on drupal 7 or have a features based site configuration setup.
- `post-drush-commands`: Some sites require changes to external systems, such as solr, third party cache, or want to run `drush deploy:hook` to allow drush to run `HOOK_deploy_NAME()` as some post deploy cleanup code. See [Drush docs](https://github.com/drush-ops/drush/blob/78aa3b9d6a77aa6feb73408ee772d76d88a59e89/drush.api.php).
- `deploy-to-test`: Provides the deployment logic to get changes to the staging environment. By default, this provides the "deploy" services, syncs live to test, and a standard deploy.
- `deploy-to-live`: Provides the deployment logic to get changes to the production environment. By default, this provides backup services, the "deploy" services as well as a standard deploy.

Automatic Security Updates.
---------------------------

[](#automatic-security-updates)

POTS contains steps and scripts to automatically look for security updates and install them into the different contributed projects.

This was build making use of CircleCI PipeLine parameters to trigger the CI job that run that scripts that checks and gets the secutity updates.

To make it trigger recluntly we have a couple of options:

- Evercurrent (Recommended)
- CircleCi triggers interface

To make the Automatic security updates works for our project, we will require to follow the next steps:

- Create a new set of SSH keys to be able to push the changes back to github (github deploy key)
- (Optional) Configure the ClickUp integration, so a ticket is created for each security-update PR
- (Optional) Configure the AI integration (OpenAI)

### Steps to set the keys

[](#steps-to-set-the-keys)

When continuous integration is configured on a project, CircleCI generates a set of SSH keys and automatically adds the private key to CircleCI and the public key to GitHub. This way CircleCI will have access to the repository in GitHub, but this access is just read-only. Originally for POTS this access is enough since it only needs reading the repository on GitHub and writing on the platform where the website is hosted (Acquia, Pantheon, Platform, etc).

With the arrival of AutoSec to POTS, this set of SSH keys is no longer enough, because AutoSec requires reading the repository, executing the security updates, and sending the changes to GitHub, therefore starting with AutoSec it is necessary to have read/write keys. CircleCI cannot generate keys with write access, therefore it is necessary to externally create a set of SSH keys and manually add them to both CircleCI and GitHub.

1. The keys must be generated, either with a command in the console through [this guide](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) or they can also be generated through [1password](https://developer.1password.com/docs/ssh/manage-keys/).
2. Add the private key to CircleCI: `Project Settings -> SSH keys -> Additional SSH Keys`.
3. Add the public key to GitHub: `Project Settings -> Deploy Keys`.

### Steps to set the ClickUp integration (optional)

[](#steps-to-set-the-clickup-integration-optional)

When configured, AutoSec creates a ClickUp task for each security-update PR and links the task URL in the PR body. Ticketing is handled by `scripts/security-updates/create-clickup-ticket` and is entirely optional — if it is not configured, AutoSec still updates packages and opens the PR, just without a ticket.

The API token is a CircleCI secret; the rest of the settings travel in the `click-data`pipeline parameter (a JSON blob) so they can be set per-trigger without touching config:

1. **Token** — add a CircleCI project env var `CU_TOKEN` with your ClickUp API token (`Project Settings -> Environment Variables`). Kept out of `click-data` because pipeline parameters are readable via the CircleCI API/UI.
2. **`click-data`** — the external trigger POST that sets `run-sec-updates-check` also sends `click-data`, a JSON object with these keys:

    keyrequiredvalue`list_id`yesClickUp list the task is created in`client_id`yesvalue for the "Client" custom field (a **drop-down option UUID**)`status`noa status **name** on the list (omit to use the list's default)`assignee_id`noClickUp user id to assignExample: `{"list_id":"901327866278","client_id":"","status":"in progress"}`

#### Finding the ids (with `CU_TOKEN` set)

[](#finding-the-ids-with-cu_token-set)

```
# list_id — also visible in the list URL: .../v/li/
curl -s -H "Authorization: $CU_TOKEN" \
  https://api.clickup.com/api/v2/team//space | jq '.spaces[] | {id, name}'
curl -s -H "Authorization: $CU_TOKEN" \
  https://api.clickup.com/api/v2/space//list | jq '.lists[] | {id, name}'

# client_id — the "Client" custom field is a drop-down; use an option's UUID (.id), not a name.
curl -s -H "Authorization: $CU_TOKEN" \
  https://api.clickup.com/api/v2/list//field \
  | jq '.fields[] | select(.name=="Client") | {type, options: .type_config.options}'

# status — use the status NAME (not id/uuid). Omit the field to use the list default.
curl -s -H "Authorization: $CU_TOKEN" \
  https://api.clickup.com/api/v2/list/ | jq -r '.statuses[].status'
```

Note: ClickUp validates `status` before custom fields, so a bad `status` can mask a bad `client_id`. If a create returns HTTP 400, check the `ECODE`: `CRTSK_001` = status name not found; `FIELD_011` = the `client_id` isn't a valid drop-down option.

### Steps to set the AI key (optional)

[](#steps-to-set-the-ai-key-optional)

AutoSec can use AI to generate functional testing steps for the packages it updates automatically. These steps are added to the PR body, giving the developer performing the tests useful guidance.

The AI integration uses the OpenAI API, so a key must be generated and added to CircleCI. Each request has a cost, so the key is entirely optional: the script checks whether `OPENAI_API_KEY` is set and, if it isn't, simply skips the AI request. Any AI failure is also non-fatal — the security PR is still created without the AI section.

1. Generate a new API Key: navigate to the [OpenAI platform](https://platform.openai.com/login?launch), log in, and open the API console.
2. Navigate to "API Keys" in the left sidebar (hover on the OpenAI logo).
3. Click the "Create new secret key" button and copy the value.
4. Add the API Key to CircleCI: `Project Settings -> Environment Variables`.
5. Click the "Add Environment Variable" button.
6. Name it `OPENAI_API_KEY` and paste the value from step 3.
7. (Optional) Add an `OPENAI_MODEL` env var to choose the model. When unset it defaults to `gpt-4o-mini`.

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance74

Regular maintenance activity

Popularity31

Limited adoption so far

Community21

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~68 days

Recently: every ~120 days

Total

27

Last Release

21d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c0e61c319d853fdc35670358f4d441cfc1167a8e0fbce4f075ca707c916a3fe8?d=identicon)[fourkitchens](/maintainers/fourkitchens)

![](https://www.gravatar.com/avatar/7f6dccf44bae9cebd5c82e58bc1cfca9b72d7df18b21d5c38cfae299f221a29b?d=identicon)[generalredneck](/maintainers/generalredneck)

---

Top Contributors

[![generalredneck](https://avatars.githubusercontent.com/u/526491?v=4)](https://github.com/generalredneck "generalredneck (54 commits)")[![rigoucr](https://avatars.githubusercontent.com/u/2217827?v=4)](https://github.com/rigoucr "rigoucr (42 commits)")[![dalin-](https://avatars.githubusercontent.com/u/1127349?v=4)](https://github.com/dalin- "dalin- (10 commits)")[![mdlutz24](https://avatars.githubusercontent.com/u/14239375?v=4)](https://github.com/mdlutz24 "mdlutz24 (8 commits)")[![randallquesadaa](https://avatars.githubusercontent.com/u/48957125?v=4)](https://github.com/randallquesadaa "randallquesadaa (3 commits)")[![edwtorba](https://avatars.githubusercontent.com/u/2343393?v=4)](https://github.com/edwtorba "edwtorba (2 commits)")[![heatherwoz](https://avatars.githubusercontent.com/u/2915691?v=4)](https://github.com/heatherwoz "heatherwoz (1 commits)")[![ccjjmartin](https://avatars.githubusercontent.com/u/12279982?v=4)](https://github.com/ccjjmartin "ccjjmartin (1 commits)")

### Embed Badge

![Health badge](/badges/fourkitchens-pots/health.svg)

```
[![Health](https://phpackages.com/badges/fourkitchens-pots/health.svg)](https://phpackages.com/packages/fourkitchens-pots)
```

###  Alternatives

[pomander/pomander

Deployment for PHP

19615.7k2](/packages/pomander-pomander)[symfony-tools/docs-builder

The build system for Symfony's documentation

3668.5k1](/packages/symfony-tools-docs-builder)[enygma/composerclean

An additional command for Composer that removes configured files/directory

171.8k](/packages/enygma-composerclean)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
