Tooling
The PHP scripts that consumer projects run for building, provisioning,
database work, deployment, notifications, and helpers such as doctor and
info live in .vortex/tooling/. This page is for contributors who change
them: it covers the package layout, the script conventions, the test
levels, and how the package gets published. To use the scripts in a
project, see Architecture > Automation
scripts.
The scripts are published as the standalone
drevops/vortex-tooling
Composer package. Consumer projects install the package and run the
user-facing scripts, the ones listed under bin in the package
composer.json, from vendor/bin/vortex-*. The other scripts, such as the
per-channel vortex-notify-* ones, run through those entry points.
Package layout
The following table lists the contents of .vortex/tooling/:
| Path | Purpose |
|---|---|
src/ | The shipped scripts and their shared helpers.php |
composer.json | The package definition, with the user-facing scripts under bin and no version field |
README.md | The package readme, which ships with the scripts |
tests/Unit/ | PHPUnit unit tests covering the shipped scripts |
tests/Self/, tests/Traits/, tests/Fixtures/ | The mocking infrastructure that the unit tests use, and its own tests |
playground/ | Manual scripts that hit live services, such as the Acquia and Lagoon database fetches; not automated |
phpcs.xml, phpstan.neon, rector.php, check-no-exit.php | The lint configuration and checks |
phpunit.xml | The PHPUnit configuration |
.gitattributes marks everything except src/, composer.json, and
README.md as export-ignore, so those 3 make up the published archive.
While developing Vortex itself, the template's root composer.json
resolves the package from the in-tree copy through a path repository with
a pinned version. The CLI strips that entry so consumer sites resolve the
published package from Packagist. The same version is also pinned in
scripts/vortex-tooling.sh and .vortex/tests/phpunit/Traits/SutTrait.php;
Release > Release process lists every spot
to bump.
Script conventions
The shipped scripts are PHP and use PHP internals wherever possible, so a consumer site needs no extra host binaries. Every script follows the same pattern:
- A
helpers.phpinclude, which also loads.envand.env.localwhile letting real environment variables win - Variables read through
getenv_default()andgetenv_required(), with their fallback chains - The shared output helpers
The output helpers have a strict contract:
INFO()opens and closes an operation.TASK()announces work that's starting and reports its outcome. It takes both the starting and the finishing message, so a task always closes.PASS()reports success on its own, for a check that holds or a step that's skipped or finished.NOTE()is a standalone remark that starts no task.FAIL()reports the failure and aborts.
TASK('Disabling Search API Solr server.', 'Disabled Search API Solr server.', function (): void {
drush('search-api:server-disable solr');
});
When the body returns, TASK() prints [ OK ] and the finishing message.
The body signals failure by throwing: TASK() reports the thrown message
as [FAIL] and stops the script.
The scripts stop with quit() instead of exit, so the unit tests can
intercept the exit code. composer lint runs check-no-exit.php, which
fails on any exit call in src/.
Consumer projects that need to alter a shipped script do so with a
cweagans/composer-patches patch, never by overriding it at runtime.
Add a script
To add a user-facing script, follow these steps:
- Create it in
src/asvortex-<name>, following the script conventions. - Add
src/vortex-<name>to thebinlist in.vortex/tooling/composer.json.
Composer creates a vendor/bin entry only for the scripts in that list.
Leave helper scripts off it: vortex-notify, for example, runs each
vortex-notify-* channel script by path from src/.
Testing
Tests cover the scripts at 3 levels:
-
Unit - PHPUnit tests in
tooling/tests/Unit/cover the shipped scripts with external commands mocked. Most test classes are named after the script they cover, without itsvortex-prefix, such asDeployLagoonTestforvortex-deploy-lagoon. Run them from.vortex/:cd .vortexahoy test-tooling# Run a single test class.ahoy test-tooling -- --filter=DeployLagoonTestTo check the code style and static analysis, run
ahoy lint-toolingfrom.vortex/. -
Integration - the template's PHPUnit functional tests in
.vortex/tests/run the scripts end-to-end. See Template > Testing. -
Manual -
tooling/playground/holds scripts that hit live services. They aren't automated.
Publishing
The Vortex - Publish tooling workflow
(.github/workflows/vortex-publish-tooling.yml) mirrors .vortex/tooling/
to the drevops/vortex-tooling
repository on every push to main, 2.x, and any branch whose name
contains vortex-tooling, matching the source branch name.
Each push publishes 1 commit to the mirror, an empty one when nothing in
.vortex/tooling/ changed. Its subject matches the subject of the pushed
commit, and its body records provenance in 2 lines,
Source: drevops/vortex@<sha> and Branch: <branch>. A branch that's new
to the mirror starts there as an orphan with no shared history. Treat the
mirror as read-only, because each publish replaces its files with the
contents of .vortex/tooling/.
To confirm a publish, open the Vortex - Publish tooling run for your
push. Its publish step ends with
Published 'drevops/vortex@<sha>' to drevops/vortex-tooling#<branch>.
The workflow doesn't set a package version: Packagist reads it from the
mirror's tags and branch names. So never hardcode a version in the
package composer.json.
You tag tooling releases on the mirror repository. When the tooling has changed since the last release, tag it before the Vortex release, so the template can require the new tag. See Release > Tagging.