Skip to main content
Version: v1

Deployment

Deployment puts the code that passed CI on your hosting platform. This page is for the lead or DevOps engineer who sets up deployments for a project built from Vortex. It covers choosing the deployment types, what triggers a deployment and how to skip or gate a deployment.

The vortex-deploy router script runs every deployment by handing off to 1 script per deployment type. It ships in the drevops/vortex-tooling Composer package and installs at vendor/bin/vortex-deploy.

The CI pipeline's deploy job runs the router after the build and lint jobs pass.

On GitHub Actions, a manual deployment runs the deploy job on its own and skips the checks. It works for every type except artifact, which needs the codebase that the build job exports. With artifact in the list, the manual deployment fails before the other types run. Outside CI, ahoy deploy runs the same script from your machine after you confirm.

The deployment scripts read their settings from environment variables. Each script loads .env from the project root, then .env.local when it exists. A variable already set in the CI job's environment wins over both files.

The tables on the deployment type pages give each variable's Location:

  • .env means a value committed with the project.
  • CI means a value set in your CI provider: a project environment variable on CircleCI, or a repository variable or secret on GitHub Actions. A GitHub Actions variable reaches the script only when the workflow's Deploy step passes it.

$VORTEX_DEPLOY_TYPES in .env lists the deployment types to run, separated by commas, for example VORTEX_DEPLOY_TYPES=artifact,webhook. The router supports 3 types:

  • webhook - calls a webhook URL with curl.
  • artifact - packages the built codebase as an artifact and pushes it to a remote Git repository.
  • lagoon - asks the Lagoon platform, through the Lagoon CLI, to deploy the branch or pull request.

The types always run in the same order, artifact, then webhook, then lagoon, whatever the order you list them in. The router matches the names as substrings and doesn't validate them, so a misspelled type deploys nothing and the job still passes. An empty list stops the job with the message Missing required value for VORTEX_DEPLOY_TYPES.

The installer's default follows your hosting choice:

  • artifact for Acquia
  • lagoon for Lagoon
  • webhook for any other hosting

After the code lands on Acquia or Lagoon, the hosting platform runs the provisioning and notification scripts. That part runs on the hosting side, outside the deploy job, so Hosting and Notifications cover it.

Expand to see deployment in the complete code lifecycle
Local Development
═════════════════════════════════════════════════════════════════════════════════════════
Developer writes code ──► Build and test locally ──► Commit changes
│
▼
Git Repository
═════════════════════════════════════════════════════════════════════════════════════════
Push to remote branch ──► Open/Update Pull Request
│
▼
┌─ CI Pipeline ────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌─ Database Job (Nightly) ───────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Scheduled ──► Download production ──► Import and export ──► Store database cache │ │
│ │ trigger database to validate the dump │ │
│ │ │ │
│ └─────────────────────────────────────┬──────────────────────────────────────────────┘ │
│ │ Provides cached database │
│ ▼ │
│ ┌─ Lint Job ────────────┐ ┌─ Database Job ────────────────┐ ┌─ Audit Job ──────────┐ │
│ │ │ │ ◆ Nightly cache exists? │ │ Composer audit │ │
│ │ Composer validate │ │ Yes ──► job succeeds │ │ (advisories) │ │
│ │ ▼ │ │ No ──► download, validate, │ │ ▼ │ │
│ │ Hadolint │ │ store cache │ │ npm audit │ │
│ │ ▼ │ └───────────────┬───────────────┘ │ (advisories) │ │
│ │ DCLint │ ▼ │ ▼ │ │
│ │ ▼ │ ┌─ Build Job ───────────────────┐ │ Gitleaks │ │
│ │ Build CLI container │ │ Code assembly │ │ (committed secrets) │ │
│ │ ▼ │ │ Docker, Composer deps, │ │ │ │
│ │ Composer normalize │ │ NPM deps, assets │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ PHPCS │ │ Website setup │ │ │ │
│ │ ▼ │ │ Import cached DB, drush │ │ │ │
│ │ PHPStan │ │ deploy, custom scripts │ │ │ │
│ │ ▼ │ │ ▼ │ │ │ │
│ │ Rector │ │ Testing │ │ │ │
│ │ ▼ │ │ Jest ──► PHPUnit ──► Behat │ │ │ │
│ │ Twig CS Fixer │ └───────────────┬───────────────┘ │ │ │
│ │ ▼ │ │ │ │ │
│ │ Gherkin Lint │ │ │ │ │
│ │ ▼ │ │ │ │ │
│ │ ESLint / Stylelint │ │ │ │ │
│ │ │ │ │ │ │
│ └──────────┬────────────┘ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ │ │ │
│ ┌─ Deployment Job ─────────────────────────────────────────┐ │ │ │
│ │ │ │ │ │
│ │ Webhook Artifact Lagoon │ │ Does not gate │ │
│ │ Call URL Package artifact Run Lagoon CLI deploy │ │ deployment │ │
│ │ │ │ │ │
│ └──────────────────────────────────────────────────────────┘ └──────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────────────────┘
│
▼
Hosting Platform
═════════════════════════════════════════════════════════════════════════════════════════
◆ Environment ──No──► Sync DB from production ───┐
exists? │
│ Yes ▼
└──────────────────────────────────► drush deploy ──► Custom scripts ──► Notifications


Available Environments
═════════════════════════════════════════════════════════════════════════════════════════
┊ PR Environment ┊ Dev Staging Production
┊ (auto-removed) ┊ develop branch main branch production branch or tag

Deployment targets​

Vortex deploys branches, pull requests and tags. The CI configuration files decide which of them deploy. The hosting platform decides how each one maps to an environment.

On GitHub Actions, a push to any of these branches triggers a deployment by default:

  • production
  • main
  • master
  • develop
  • release/**
  • hotfix/**
  • project/**

The router then deploys the branch with each type in $VORTEX_DEPLOY_TYPES.

On GitHub Actions, a pull request deploys its branch when it's opened, updated or reopened against a branch in the preceding list, a feature/* branch or a bugfix/* branch. Depending on the hosting platform, a pull request deployment can create a temporary environment named after it, such as pr-123 on Lagoon.

On GitHub Actions, short-lived feature/* and bugfix/* branches deploy through their pull requests rather than direct pushes, because deploying both would double every CI run and every deployment. Branches that automated dependency updates create (deps/*) never deploy, on either CI provider.

CircleCI matches branch names against regular expressions. Its patterns also match pushes to feature/*, bugfix/* and ci* branches and to major version branches such as 2.x. The patterns match release/* and hotfix/* branches only when the name after the slash is a version or a date. CircleCI builds each push: when a deployed branch has an open pull request, the build deploys it as that pull request, such as pr-123.

A project/* branch is a long-lived branch for a larger feature or project that spans several pull requests. A migration branch is a typical case: its code and configuration aren't ready to merge into develop, but it needs a remote environment for testing. You sync such a branch with develop by hand.

On GitHub Actions, a project/* branch deploys on direct pushes, and its pull requests don't deploy, so each change deploys once. CircleCI skips the deployment of a project/* branch whenever the branch has an open pull request.

Tags deploy too. GitHub Actions deploys any pushed tag. CircleCI deploys tags that look like a semantic version (1.2.3, 1.2.3-rc.1) or a date (2023-04-17, 2023-04-17.1). A tag runs in tag mode (VORTEX_DEPLOY_MODE=tag), and each deployment type handles it in its own way:

  • artifact pushes to a deployment/[tags:-] branch, named after the tags on the deployed commit.
  • webhook calls its URL, as it does for a branch.
  • lagoon skips the deployment, because Lagoon doesn't support tag deployments.

The provider pages list the exact patterns and show how to change them. See GitHub Actions > Update trigger branches and CircleCI > Update deployment branches.

Deployment action​

By default, a deployment keeps the environment's existing database. $VORTEX_DEPLOY_ACTION sets what a deployment does:

  • deploy - deploys the code and keeps the environment's database. An empty value, the default, does the same.
  • deploy_override_db - deploys the code and replaces the environment's database during provisioning with a copy from the configured database source, which is production by default on Lagoon. On a Lagoon production environment, .lagoon.yml sets VORTEX_PROVISION_OVERRIDE_DB=0, so production keeps its database. A site that provisions from a profile reads that value from .env instead.
  • destroy - removes the deployed environment, on platforms that support it (Lagoon).

Only the Lagoon deployment reads the action. VORTEX_DEPLOY_LAGOON_ACTION overrides it for Lagoon alone. On GitHub Actions, checking override_db on a manual deployment sets the action to deploy_override_db.

Skip deployments​

To skip every deployment, set VORTEX_DEPLOY_SKIP to 1. CI still builds and tests the code, and the deploy job stops before it deploys anything. Its log shows Found flag to skip all deployments.

On GitHub Actions, the workflow reads the skip and gate variables from repository variables of the same name:

  • VORTEX_DEPLOY_SKIP
  • VORTEX_DEPLOY_ALLOW_SKIP
  • VORTEX_DEPLOY_SKIP_PRS
  • VORTEX_DEPLOY_SKIP_BRANCHES
  • VORTEX_DEPLOY_ALLOW_LABEL

On CircleCI, set them in the project's environment variables or in .env.

Skip deployments for specific pull requests or branches​

To skip specific pull requests or branches:

  1. Set $VORTEX_DEPLOY_ALLOW_SKIP to 1.
  2. List the pull requests in $VORTEX_DEPLOY_SKIP_PRS, the branches in $VORTEX_DEPLOY_SKIP_BRANCHES or both, as the following sections show.

Each list takes a single value or a comma-separated list without spaces. Entries match exactly, with no wildcards.

Confirm that the next build of a listed pull request or branch skips its deployment. The deploy job log shows Found PR 42 in skip list. or Found branch feature/test in skip list., followed by Skipped deployment and your deployment types.

Skip specific pull requests​

Set $VORTEX_DEPLOY_SKIP_PRS to the pull request numbers. Use the bare number, without a pr- prefix:

# Skip a single PR
VORTEX_DEPLOY_ALLOW_SKIP=1
VORTEX_DEPLOY_SKIP_PRS=42

# Skip multiple PRs
VORTEX_DEPLOY_ALLOW_SKIP=1
VORTEX_DEPLOY_SKIP_PRS=42,123,456

Skip specific branches​

Set $VORTEX_DEPLOY_SKIP_BRANCHES to the branch names. A pull request build is skipped by its branch name too, because CI passes the branch name with the pull request number:

# Skip a single branch
VORTEX_DEPLOY_ALLOW_SKIP=1
VORTEX_DEPLOY_SKIP_BRANCHES=feature/test

# Skip multiple branches
VORTEX_DEPLOY_ALLOW_SKIP=1
VORTEX_DEPLOY_SKIP_BRANCHES=feature/test,hotfix/urgent,project/experimental

Combined usage​

A match in either list skips the deployment:

VORTEX_DEPLOY_ALLOW_SKIP=1
VORTEX_DEPLOY_SKIP_PRS=42,123
VORTEX_DEPLOY_SKIP_BRANCHES=feature/test,hotfix/urgent

Gate deployments on a PR label​

The label gate makes pull request deployments opt-in: a pull request gets an environment only after someone labels it. The skip lists work the other way: everything deploys except what they list. Use the gate to limit the number and cost of per-PR environments, or to keep work-in-progress pull requests out of environments.

To turn the gate on, set $VORTEX_DEPLOY_ALLOW_LABEL to the name of the label that authorizes deployment:

VORTEX_DEPLOY_ALLOW_LABEL=deploy

With this setting, a pull request deploys only when it carries the deploy label. The name matches exactly, including case. When the variable is empty or unset, the default, the gate is off.

The gate applies only to pull request builds. Branch and tag deployments have no pull request label, so the gate never blocks them.

The router reads the pull request's labels from $VORTEX_DEPLOY_PR_LABELS, a comma-separated list that CI fills in from the pull request event:

  • GitHub Actions fills it in for you. The workflow has no labeled trigger, so a label added to an open pull request takes effect on the next push. A manual deployment of a pull request carries no labels, so the gate skips it.
  • CircleCI doesn't provide labels, so to use the gate there, fill in $VORTEX_DEPLOY_PR_LABELS yourself, for example from the GitHub API.

Confirm that the gate works: the deploy job of a pull request without the label logs PR 123 does not carry the "deploy" label. and deploys nothing.

The label gate and the skip lists combine. The router checks the skip lists first, and a match always wins. A pull request listed in $VORTEX_DEPLOY_SKIP_PRS is skipped even when it carries the gate label.

See also​

The following pages cover each deployment type and the notifications sent after a deployment:

TopicDescription
WebhookDeploy by calling a webhook URL
ArtifactDeploy code artifacts to remote repositories
LagoonDeploy to the Lagoon hosting platform
NotificationsSend deployment notifications