Skip to main content
Version: v1

Artifact deployment

In an artifact deployment, CI builds your codebase and pushes it as an artifact to a remote Git repository. Use it for a hosting platform that deploys pre-built code from a Git repository it controls, such as Acquia. The artifact carries only what production needs.

This page is for the lead or DevOps engineer who sets up artifact deployments. It explains how CI builds and pushes the artifact, how to configure the push and how to control which files the artifact carries.

How it works​

When $VORTEX_DEPLOY_TYPES includes artifact, CI and the deployment script go through these steps:

  1. The build job builds the stack and copies the codebase out of the cli container before development dependencies install, so the copy holds production dependencies only.
  2. The deploy job restores that copy and runs the deployment script, which downloads the Git artifact tool and verifies its checksum.
  3. The script copies .git and .gitignore.artifact from the repository checkout into the copied codebase. The tool then applies the .gitignore.artifact rules to control which files are included.
  4. The tool pushes the artifact to the configured remote repository. The optional stale branch cleanup runs after a successful push.
  5. The hosting platform then deploys from that repository.

Configuration​

Configure the push with the variables in the following table, then follow the setup steps.

Environment variables​

The Deployment overview explains the Location values and how the script loads .env. The following table lists the variables that control the push:

VariableRequiredDefaultLocationDescription
VORTEX_DEPLOY_ARTIFACT_GIT_REMOTEYesNoneCI, or .env on CircleCIRemote repository URL for the artifact
VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAILYesNoneCI, or .env on CircleCIEmail address of the user committing to the remote repository
VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAMENoDeployment RobotCI, or .env on CircleCIName of the user committing to the remote repository
VORTEX_DEPLOY_ARTIFACT_DST_BRANCHNo[branch].envRemote branch to push to; supports tokens. Tag deployments always push to deployment/[tags:-], whatever this is set to
VORTEX_DEPLOY_ARTIFACT_SRCYes, set by the shipped CI configsNoneCIDirectory with the built codebase to package, passed to git-artifact as --source; the shipped CI configs set it to /tmp/workspace/code
VORTEX_DEPLOY_ARTIFACT_ROOTNoCurrent directoryCIRepository checkout that .git and .gitignore.artifact are copied from, passed to git-artifact as --root
VORTEX_DEPLOY_ARTIFACT_LOGNo<root>/deployment_log.txt.envPath to the deployment log file; the shipped CircleCI config sets it to /tmp/artifacts/deployment_log.txt
VORTEX_DEPLOY_ARTIFACT_SSH_FINGERPRINTNoValue of VORTEX_DEPLOY_SSH_FINGERPRINTCIFingerprint of the SSH key used to push to the remote repository
VORTEX_DEPLOY_ARTIFACT_SSH_FILENoValue of VORTEX_DEPLOY_SSH_FILE, then ~/.ssh/id_rsaCISSH key file used when no fingerprint is set

Git artifact tool covers the pinned git-artifact version and the optional stale branch cleanup. The Variables reference lists every variable with the script that reads it.

The shipped CI configs set VORTEX_DEPLOY_ARTIFACT_SRC and VORTEX_DEPLOY_ARTIFACT_ROOT for you.

On GitHub Actions, the shipped workflow passes 3 variables from repository variables of the same name:

  • VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE
  • VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL
  • VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAME

Set these 3 as repository variables. The value the workflow passes wins over .env, even when it's empty. Set the other artifact variables in .env, because the workflow doesn't pass them.

Setup​

To set up artifact deployment:

  1. Add artifact to the VORTEX_DEPLOY_TYPES variable in your .env file:

    .env
    VORTEX_DEPLOY_TYPES=artifact
  2. Set the remote repository's Git URL as VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE, where your CI provider reads it:

    • On GitHub Actions, add a repository variable under Settings > Secrets and variables > Actions > Variables.
    • On CircleCI, add a project environment variable, or set it in .env.

    In .env, the setting looks like this:

    .env
    VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE=git@github.com:your-org/your-project-artifact.git
  3. Set the email address for the deployment commits as VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL, in the same place as the remote. The following example also sets the optional user name, which replaces the default Deployment Robot:

    VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAIL="deploy@example.com"
    VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAME="Deployment Bot"

    The script sets the email and name as the runner's global Git identity, but only when the runner has no identity yet.

  4. Give CI an SSH key with write access to the remote repository:

    • On GitHub Actions, add the private key as the VORTEX_DEPLOY_SSH_PRIVATE_KEY repository secret.
    • On CircleCI, add the private key under Project Settings > SSH Keys and set its fingerprint as deploy_ssh_fingerprint in .circleci/config.yml.

    The script loads the key before it pushes and stops when the key file is missing.

Confirm that the next deployment pushed the artifact. The deploy job log shows [ OK ] Finished artifact deployment. The remote repository has a branch with the same name as the deployed branch.

Git artifact tool​

git-artifact packages and pushes files to remote repositories.

Some hosting providers, such as Acquia, restrict certain build operations, so you build the site somewhere else, then deploy the result. The tool handles that transfer. A .gitignore.artifact file controls which files go across. Each push replaces the history of the destination branch with the history of the source branch, while the source repository stays untouched.

Vortex ships 2 files for this:

CI uses them to build the artifact and push it to the remote repository, such as Acquia's, with no manual steps.

The deployment script downloads the git-artifact binary from GitHub Releases and checks its SHA256 checksum before running it. A mismatch stops the deployment.

These variables control the version and the checksum:

  • VORTEX_DEPLOY_ARTIFACT_GIT_ARTIFACT_VERSION: Version to download (default: 1.9.0).
  • VORTEX_DEPLOY_ARTIFACT_GIT_ARTIFACT_SHA256: Expected SHA256 checksum of the binary (default: the checksum of the default version).

Change them together, and set both in .env. The checksum matches 1 exact binary, so a new version with the old checksum fails the check. To get the checksum of another version, use either of these:

  • The SHA256 digest that GitHub shows for the release's git-artifact asset
  • The output of sha256sum on the downloaded binary

Stale branch cleanup​

With the default [branch] destination, each source branch deploys to a branch of the same name. Over time, the destination repository collects branches for source branches that no longer exist. Vortex can prune these stale branches after each successful push.

Cleanup is opt-in. These variables control it, and they go in .env:

  • VORTEX_DEPLOY_ARTIFACT_CLEANUP_PATTERN: branches eligible for pruning. Cleanup runs only when this variable is set, and it's empty by default. The value is a comma-separated list of globs, for example feature/*,bugfix/*, or a single regular expression literal, for example /^feature\/.+$/. A branch matching any pattern is eligible.
  • VORTEX_DEPLOY_ARTIFACT_CLEANUP_AGE: the number of days since a matching branch's last commit after which the branch counts as stale (default: 7).

Cleanup keeps the newly pushed branch and the destination repository's default branch. A failed cleanup doesn't fail the deployment.

Artifact file control​

The .gitignore.artifact file controls which files go into the deployment artifact. During deployment, git-artifact applies its rules in place of the standard .gitignore, so these rules decide what reaches the hosting Git repository.

Vortex writes .gitignore.artifact as a deny list: every file deploys by default, and the file lists only what stays out of production. The pre-configured .gitignore.artifact deploys everything a production Drupal site needs:

  • vendor/
  • The built webroot: Drupal core, compiled theme assets, contributed modules and contributed themes
  • config/
  • drush/
  • scripts/
  • .env

It excludes these groups, shown here with their main entries:

  • Version control, IDE and OS files (.git, .idea, .vscode, .DS_Store).
  • Development, continuous integration and AI configuration (.ahoy.yml, .circleci, .claude, .docker, .github, CLAUDE.md, docker-compose.yml), plus the database cache key files that the GitHub Actions workflow writes (db_cache_*).
  • Documentation and testing configuration (docs, tests, behat.php, phpunit.xml, phpcs.xml).
  • Dependency manifests and lock files not needed at runtime (composer.lock, package.json, package-lock.json).
  • Drupal scaffold's non-production files (default.settings.local.php, example.services.local.yml).
  • Credentials, local overrides, caches and content files (auth.json, .env.local, settings.local.php, .data, web/sites/*/files).
  • Custom theme asset sources, since only the theme's compiled build/ output is deployed.

Customize the artifact​

Because the file is a deny list, a new file you add to the project deploys automatically. Edit .gitignore.artifact only to keep an additional file out of the artifact, or to re-include something that a broader rule excludes:

.gitignore.artifact
# Keep an additional development file out of the artifact.
/RELEASE.md

# Re-include theme images that the artifact excludes by default.
!/web/themes/custom/your_site_theme/images

See also​

The following page covers the hosting side of an artifact deployment: