Skip to content

Deploy configuration from CI/CD

Goal: import a Source CMS site’s configuration from the CI system you already run, on every push to your main branch.

  • A pipeline job that imports the committed configuration on every push to your main branch, with no prompts.
  • A job that fails when the site refuses the import.
  • A working copy with .acquia/config committed and the site recorded, from Sync configuration with acli.
  • A Source CMS site you hold site-administrator rights on. Organization administrators hold those rights today; see what the pipeline’s credentials can do before you create the token.
  • Cloud Platform API credentials (key and secret). Create them as shown on the Cloud Platform API page.
  • A CI system that can run a Linux x86_64 or macOS aarch64 job and hold two secrets.
  1. Store a Cloud Platform API key and secret as CI secrets, and expose them as ACLI_KEY and ACLI_SECRET, the names acli reads in place of acli auth:login. The examples store them as ACQUIA_CLOUD_KEY and ACQUIA_CLOUD_SECRET.

    Supply the site with a committed .acquia-cli.yml or --site, as on Sync configuration with acli, and pass --yes to the import.

  2. Each example installs the native acli binary and imports on every push to main.

    Only one import runs per site at a time, so a job that starts while the previous one is still importing is refused. Each example first waits for a running import to clear: acli source:cms:config:push --status reports the site’s latest import without starting one, and exits 2 while it is still running. The CI system’s retry handling repeats that check until it exits anything else.

    GitHub Actions has no built-in retry for one step, so its example uses the community action nick-fields/retry. Bitbucket retries a step on any failure, so its check runs in a step of its own.

    name: Push Source config
    on:
    push:
    branches: [main]
    jobs:
    push-config:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Install Acquia CLI
    run: |
    curl -fsSL -o acli.tar.gz https://github.com/acquia/cli/releases/latest/download/native-acli-linux-x86_64.tar.gz
    tar -xzf acli.tar.gz
    sudo mv acli /usr/local/bin/acli
    - name: Wait for any running import to clear
    uses: nick-fields/retry@v3
    env:
    ACLI_KEY: ${{ secrets.ACQUIA_CLOUD_KEY }}
    ACLI_SECRET: ${{ secrets.ACQUIA_CLOUD_SECRET }}
    with:
    max_attempts: 5
    retry_wait_seconds: 60
    timeout_minutes: 1
    retry_on_exit_code: 2 # only retry while an import is running
    # 2 = running, retry; anything else (including a previous import's own refusal) means proceed
    command: 'acli source:cms:config:push --status --site=my-site-id; [ $? -eq 2 ] && exit 2 || exit 0'
    - name: Push configuration
    env:
    ACLI_KEY: ${{ secrets.ACQUIA_CLOUD_KEY }}
    ACLI_SECRET: ${{ secrets.ACQUIA_CLOUD_SECRET }}
    run: acli source:cms:config:push --site=my-site-id --yes

    The native binary is built for Linux x86_64 and macOS aarch64 only. On an ARM Linux or Windows runner, use acli.phar with PHP instead.

  3. A refused or failed import fails the job. For what each outcome means, see Read the outcome.

Syncing requires site-administrator rights, which today only organization administrators hold. The pipeline’s token can therefore reach every site in the organization, not only the one it syncs. Keep it in your CI system’s secret store, limit who can run the pipeline, and rotate it with your other Acquia credentials.

The job runs the same import as a terminal session. ACLI_KEY and ACLI_SECRET replace acli auth:login, and --yes with a known site replaces every prompt. A refusal appears only in the command’s output, so read the failed job’s log.

A sync is already running for the site.

The second import is refused without touching the site, and nothing is queued. Rerun the job once the running import finishes, or raise the wait step’s retry budget.

For the site’s other refusals, see When something goes wrong on the acli page.

Was this page helpful?