Skip to main content
Version: v1

Artifact deployment

Artifact deployment packages your built codebase and pushes it to a remote Git repository. Use it for hosting platforms like Acquia, which deploy from a Git repository of their own and expect pre-built code in it. CI does the build, and 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 it installs development dependencies, 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 .envRemote repository URL for the artifact
VORTEX_DEPLOY_ARTIFACT_GIT_USER_EMAILYesNoneCI or .envEmail address of the user committing to the remote repository
VORTEX_DEPLOY_ARTIFACT_GIT_USER_NAMENoDeployment RobotCI or .envName 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, so you don't set them yourself.

On GitHub Actions, the shipped workflow passes the remote, the user email, and the user name from repository variables of the same name, so set them there. A value in .env doesn't reach the script for these 3, because the value the workflow passes wins, even when it's empty. The workflow passes no other artifact variable, so set the rest in .env.

Setup​

To set up artifact deployment, complete these steps:

  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 them as the runner's global Git identity, but only when the runner doesn't have one 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., and 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, like Acquia, restrict certain build operations, so you develop and build the site somewhere else before you deploy it. This 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 and leaves the source repository untouched.

Vortex comes with a pre-configured .gitignore.artifact file and the vortex-deploy-artifact deployment script from the drevops/vortex-tooling Composer package. Together, they build the artifact in CI and push it to the remote repository, such as Acquia's, with nothing to do by hand.

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. The checksum matches 1 exact binary, so a new version with the old checksum fails the check. For the checksum of another version, use the SHA256 digest that GitHub shows for the release's git-artifact asset, or download the binary and run sha256sum on it. Set both variables in .env.

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. Setting a non-empty value enables cleanup; leaving it empty (the default) disables it. 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).

The newly pushed branch and the destination repository's default branch are never deleted, and cleanup never fails a deployment that already succeeded.

Artifact file control​

The .gitignore.artifact file controls which files go into the deployment artifact. During deployment it takes the place of the standard .gitignore, so its rules decide what reaches the hosting Git repository and the project's usual ignore rules don't apply.

Vortex writes .gitignore.artifact as a deny list: every file deploys by default, and the file lists only what has to stay out of production. The pre-configured .gitignore.artifact deploys everything a production Drupal site needs: vendor/, the built webroot (Drupal core, contributed modules and themes, and compiled theme assets), config/, drush/, scripts/, and .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).
  • Theme asset sources, since only the compiled build/ output is deployed.

Customizing 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

Use cases​

Artifact deployment fits these hosting setups:

  • Acquia hosting, which requires code artifacts pushed to Acquia's Git repository
  • Any other platform that deploys from a Git repository it controls

See also​

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