Deploy from GitHub Actions
Deploy from GitHub Actions
Once a repository's projects declare [cloud] blocks (see Deploying Jobs), a GitHub Actions workflow can run trilogy cloud sync on every merge to main. Merged changes reach production without anyone running a command.
The workflow authenticates with a deploy token: an org-scoped token that can only create, update and delete the jobs synced from this repository.
One-Command Setup
From a clone of the repository, signed in with trilogy cloud login:
trilogy cloud --org acme bootstrap models --prune --write-workflow
models is the directory to sync; omit it to sync the whole repository. bootstrap does three things:
- Syncs
modelsto production under your own login, so the jobs exist and record this repository as their source. - Mints a deploy token pinned to that source and prints it once.
- Writes
.github/workflows/cloud-sync.yml, which runs the same sync on every push tomain.
Then store the token:
- In GitHub, open Settings → Secrets and variables → Actions.
- Add a repository secret named
TRILOGY_CLOUD_TOKENholding the printed value. - Commit the workflow file and merge it.
Add --dry-run to see what bootstrap would deploy and mint without doing either.
The Workflow
bootstrap --write-workflow writes a minimal workflow. This fuller version adds a dry-run preview, a manual trigger and a concurrency guard:
name: Cloud Sync
on:
push:
branches: [main]
paths:
- 'models/**'
- '.github/workflows/cloud-sync.yml'
workflow_dispatch:
inputs:
dry_run:
description: 'Report what would change without writing'
type: boolean
default: true
permissions:
contents: read
# Two merges in quick succession would otherwise race on the same jobs.
concurrency:
group: cloud-sync
cancel-in-progress: false
env:
SYNC_ROOT: models
TRILOGY_CLOUD_ORG: acme
TRILOGY_CLOUD_TOKEN: ${{ secrets.TRILOGY_CLOUD_TOKEN }}
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
# sync reads the branch and remote from .git to pick its target.
ref: ${{ github.ref_name }}
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- run: pip install pytrilogy
- name: Show what would change
run: trilogy cloud --org "$TRILOGY_CLOUD_ORG" sync "$SYNC_ROOT" --dry-run
- name: Sync
if: ${{ github.event_name != 'workflow_dispatch' || !inputs.dry_run }}
run: trilogy cloud --org "$TRILOGY_CLOUD_ORG" sync "$SYNC_ROOT" --prune
A merged pull request is a push to main, so this runs once per merge. The paths filter skips merges that touch nothing under models/.
Notes on the details:
--orggoes beforesync. It is an option oftrilogy cloud, not ofsync. It is needed because the CLI reads[cloud].orgonly from atrilogy.tomlat or above the working directory, and the repository root usually has none.- Pin Python to 3.11–3.13.
pytrilogypublishes wheels for those versions; on a newer interpreterpipfalls back to a slow source build. --pruneneeds a token minted with--prune. It deletes jobs whose directory was removed in the merge. Drop it from both if you prefer to delete jobs by hand.- The token reads
TRILOGY_CLOUD_TOKENfrom the environment. Do not pass it as--token, which puts it in the process arguments.
Preview a Pull Request
To show reviewers what a merge would deploy, run the dry run on pull requests too. --production compares against production regardless of the PR's branch:
on:
pull_request:
paths:
- 'models/**'
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-python@v6
with:
python-version: '3.13'
- run: pip install pytrilogy
- run: trilogy cloud --org acme sync models --production --dry-run
env:
TRILOGY_CLOUD_TOKEN: ${{ secrets.TRILOGY_CLOUD_TOKEN }}
GitHub does not expose repository secrets to pull requests from forks, so the preview only runs for branches in the repository itself.
What a Deploy Token Can Change
A deploy token can create and update jobs, workspaces and schedules under its source, and with --prune, delete jobs. It cannot change these settings:
secret_envpriorityanddeadline_secondsvm_class
They affect secrets, cost or placement, so they need an owner or admin. Set them before running bootstrap, whose first sync runs under your own login. To change one later, sync from a main checkout yourself:
trilogy cloud --org acme sync models
A CI sync that would change one of them fails with a permission error.
Minting the Token Separately
bootstrap is the sync and the mint in one step. Each half is also its own command. To replace an expiring token for a repository that is already deployed:
trilogy cloud --org acme tokens create-deploy "ci-deploy (acme/models)" --source --prune
Run it from inside the checkout. A bare --source pins the token to this checkout's repository and subdirectory, the same source that sync records. Tokens expire after 90 days by default; --expires-in-days sets another lifetime.
tokens list shows every token you have minted, deploy tokens included, and tokens revoke deletes one by id:
trilogy cloud tokens list
trilogy cloud tokens revoke TOKEN_ID
Harden the Secret
A repository secret is readable by any workflow on any branch. To restrict the token to main, store it in a GitHub environment instead:
- Under Settings → Environments, create an environment, for example
cloud-deploy. - Set its deployment branch policy to
mainonly. - Add
TRILOGY_CLOUD_TOKENas an environment secret. - Add
environment: cloud-deployto the sync job.
A workflow run from any other branch then fails before it can read the token. The pull request preview above needs its own token, or a repository secret, under this setup.