Skip to main content
This tutorial demonstrates how to connect GitHub Actions to a Workflow on Anaconda Platform so that every push automatically deploys the flow. Using this pattern, merging to main updates the production deployment. Every other branch gets an isolated deployment to test against real platform compute, and deleting a branch tears its deployment down. Anaconda uses this pattern for the flow behind its package request triage intake agent, which assesses whether an open-source package is safe to add to the main channel. By the end of this tutorial, you will have:
  • A flow that deploys to production from main and to an isolated branch deployment from every other branch
  • A GitHub Actions workflow that deploys on push and on pull request
  • A GitHub Actions workflow that tears down a branch deployment when its branch is deleted

Prerequisites

  • A flow you are ready to deploy to Anaconda Platform. The flow must use the @project decorator. For background, see What is a project?
  • A GitHub repository with Actions enabled.
  • A machine user that’s connected to your github repo, or admin access to create one. For details, see Programmatic access with machine users.
  • The domain of your Anaconda Platform deployment and the name of the perimeter that CI deploys into.

Decide how your branches map to Workflows

How you choose to map branches to Workflows depends on your branching strategy, constraints, and goals. This topic guides you through one method, with the reasoning explained below. If your constraints and goals differ, your GitHub Actions will likely need to look different from the ones shown here.

Name the project and scope the trigger

Give the flow a project name with @project. If the flow responds to platform events, arm its trigger only in production. Branch deployments share the project, so a trigger armed on every branch would make each branch consume production events.
Deploy the flow with python flow.py argo-workflows create. The @project decorator namespaces every deployment under the project name, and the flag you pass before argo-workflows create determines the deployment’s name and type: Only the --production deployment arms @trigger, so the new-triage-ticket event has exactly one consumer.

Create a machine user for CI

CI authenticates as a machine user rather than a person. Create one scoped to the repository and to the perimeter CI deploys into.
1

Create the machine user

  1. Select Users in the left-hand navigation, then select the Machines tab.
  2. Click Create New.
  3. Select GitHub Actions, then enter a Name and Description.
  4. In Attributes to validate, set Organization and Repository to the repository that runs the workflow. Leave Branch empty so jobs on every branch can authenticate.
  5. Click Submit.
Setting Branch to main scopes the machine user to that branch, so jobs on other branches fail to authenticate.
2

Grant privileges in the target perimeter

Open the machine user and grant it the Execute privilege in the perimeter CI deploys into. Privileges are per perimeter, so a machine user with privileges only in the default perimeter cannot deploy into another perimeter. For details, see Roles and privileges.

Deploy on every push

Create .github/workflows/deploy.yml. This workflow deploys on every push to main, on every pull request, and on demand. It deploys to production when the ref is main, and to an isolated branch deployment otherwise.
.github/workflows/deploy.yml
The <MACHINE_USER_NAME>, <DEPLOYMENT_DOMAIN>, and <PERIMETER> values must match the values you used in the deploy workflow.
The workflow makes these decisions explicit:
  • Triggers: pushes to main, pull requests, and manual runs. Because only branches is defined under push, tag pushes do not trigger a deploy.
  • Concurrency: cancel-in-progress: true keeps one deploy per ref running, so a fast series of pushes does not race. The most recent push wins and the earlier one is canceled.
  • Permissions: id-token: write lets the job request GitHub’s OIDC token, and contents: read lets it check out the repository.
  • Fork guard: the if condition skips pull requests from forks. A fork’s OIDC token does not carry the repository claims the machine user validates, so those jobs cannot authenticate.
  • Ref to target: the job resolves the branch from GITHUB_REF_NAME, or from GITHUB_HEAD_REF for pull requests, and deploys with --production for main and --branch for everything else.
  • Branch normalization: GitHub branch names can contain / and uppercase characters, which are not valid in a Metaflow branch name. The workflow lowercases the ref and replaces every character outside a-z, 0-9, and _ with _, so Feature/Add-Scoring becomes feature_add_scoring. Use the same normalization in the teardown workflow so both operate on the same branch name.
  • Authentication: service-principal-configure --github-actions reads GitHub’s OIDC token from the job environment and exchanges it for platform credentials. No long-lived platform credentials are stored in the repository.
The deploy command passes several options before argo-workflows create:
  • --environment=fast-bakery builds a reproducible container from the flow’s declared dependencies.
  • --package-suffixes=.py,.yaml,.yml,.json packages non-Python files the flow reads at runtime, such as a config file.
  • --production or --branch selects the deployment target.
--environment, --package-suffixes, and --production or --branch are top-level Metaflow options. They must come before argo-workflows create.

Tear down a branch deployment

Create .github/workflows/teardown-branch.yml. This workflow runs when a branch is deleted and removes that branch’s deployment.
.github/workflows/teardown-branch.yml
The workflow makes these decisions explicit:
  • Trigger: the delete event, which fires for branch and tag deletions. The delete event does not support branch filters, so the job guards against tearing down production itself. The if condition runs the job only for branch deletions other than main, so tag deletions and main are skipped.
  • Ref to branch: the delete event reports the branch name in github.event.ref, such as feature/add-scoring. The workflow strips a refs/heads/ prefix defensively and applies the same normalization as the deploy workflow.
  • Safety check: the case statement is a second guard that refuses to run for an empty branch name, main, or master.
  • Teardown: flowproject teardown-branch --id "<PROJECT_NAME>/<BRANCH>" --yes removes the branch deployment. The --yes flag skips the confirmation prompt, which CI cannot answer.
Teardown deletes asset metadata, not the underlying data. To keep an asset that a feature branch produced, promote it before the branch is torn down. For details, see Project lifecycle.
To preview a teardown before it runs, use --dry-run:

Verify the loop

Confirm each path of the loop works:
  1. Push a commit to a new branch. When the deploy workflow finishes, open the Workflows view. A package_triage.test.<BRANCH>.TriageFlow deployment appears.
  2. Merge the branch to main. The deploy workflow updates package_triage.prod.TriageFlow.
  3. Delete the branch. The teardown workflow runs, and the branch deployment disappears from the Workflows view.

Next steps

To build on this tutorial: