---
title: "Automate Barbara deployments with GitHub Actions"
sidebar_label: "GitHub Actions sample"
description: "Use the barbara_github_actions_sample repository as a template to drive the full Barbara application lifecycle — version, package, register, deploy, verify, and roll back — from a single GitHub Actions workflow."
lastmod: "2026-05-13"
---

import VersionNotice from '@site/src/components/VersionNotice';
import { UpdateInProgressNotice } from '@site/src/components/VersionNotice';

<VersionNotice platformArticleVersion="v3.2.0" />
<!--
<UpdateInProgressNotice />
-->

## Overview

The <a href="https://github.com/Barbaraedge/barbara_github_actions_sample" target="_blank" rel="noopener noreferrer">**barbara_github_actions_sample**</a> repository is a minimal Python application wired to a single GitHub Actions workflow that automates the full Barbara application lifecycle: build the image, register the application in Barbara, upload a new version, deploy it to selected devices, verify health on-device, and roll back automatically if verification fails.

The app itself is intentionally trivial — an HTTP server with a `/health` probe — so you can focus on the CI/CD plumbing and reuse it as a template for your own apps.

In this article you will:

* Clone the sample and connect it to your own Barbara organization.
* Configure the GitHub variables and secrets the workflow needs.
* Declare the devices and groups where the app should be deployed.
* Trigger a release by pushing a `v*` tag and follow the pipeline end-to-end.

## Pipeline at a glance

When you push a tag matching `v*` (for example `v0.1.0`), the workflow at `.github/workflows/cicd.yml` runs nine jobs in sequence:

| # | Job | What it does |
|---|---|---|
| 1 | Test | Runs the app's unit tests inside a Python container. |
| 2 | Validate deployment targets | Resolves `deployment-targets.json` against the Barbara API and fails fast if any declared device or group does not exist. |
| 3 | Build image | Builds and pushes a multi-platform Docker image tagged with the short commit SHA, the semver version, and `latest`. |
| 4 | Package artifact | Generates a release `.zip` containing a single `docker-compose.yaml` that pins the immutable `<sha>`-tagged image. |
| 5 | Register Barbara application | Creates the application in Barbara if it does not already exist. |
| 6 | Upload Barbara version | Uploads the `.zip` as a new app version under the registered application. |
| 7 | Deploy to devices | Triggers the deployment of that version to the resolved targets. |
| 8 | Verify deployment | Polls device health and triggers a rollback if it fails within the configured timeout. |
| 9 | Create GitHub release | Publishes a GitHub release with the `.zip` attached — only after successful verification. |

The deployment targets are validated **before** the image is built. A typo in a device or group name fails the pipeline early, with no wasted build.

## Get the sample repository

Clone or fork the repo so you can push your own tags and trigger the workflow:

```bash
git clone https://github.com/Barbaraedge/barbara_github_actions_sample.git
cd barbara_github_actions_sample
```

The repository layout is:

```
.
├── app/main.py                              # HTTP app (port 8080)
├── scripts/
│   ├── barbara_api.py                       # Barbara and Keycloak request helpers
│   ├── resolve_deployment_targets.py        # Validates deployment-targets.json against Barbara
│   ├── package_docker_compose.py            # Generates the deployable docker-compose.yaml
│   ├── ensure_barbara_application.py        # Creates the Barbara app if missing
│   ├── upload_barbara_app_version.py        # Uploads the .zip as a Barbara app version
│   ├── deploy_barbara_app_version.py        # Triggers deployment on target devices
│   ├── verify_deployment.py                 # Polls health and rolls back if needed
│   └── get_container_info.py                # Retrieves container runtime info from Barbara
├── tests/test_app.py
├── .github/workflows/cicd.yml
├── deployment-targets.json
├── Dockerfile
└── docker-compose.yaml
```

Every script under `scripts/` is invoked by a job in the workflow. They use the standard library only — no extra runtime dependencies.

:::tip[Run the app locally first]

Before wiring CI/CD, smoke-test the app on your machine:

```bash
python app/main.py
curl http://localhost:8080/health    # → OK
```

This is the same `/health` endpoint the verification job polls on the edge node.

:::

## Configure GitHub variables and secrets

The workflow reads two layers of configuration: repository-level (build and registry) and environment-level (Barbara and Keycloak). The repo ships with a `production` environment defined in the workflow; you typically configure both `development` and `production`.

### Repository variables

Set these under **Settings → Secrets and variables → Actions → Variables**:

| Variable | Description | Example |
|---|---|---|
| `APP_NAME` | Logical application name in Barbara. | `Github_Actions_Sample` |
| `IMAGE_NAME` | Image name in the registry. | `github-actions-sample` |
| `REGISTRY_HOST` | Container registry host. | `bdr.barbara.tech` |
| `REGISTRY_NAMESPACE` | Namespace within the registry. | `public` |
| `APP_DEVELOPER` | Developer name shown in Barbara for the app (defaults to `Barbara`). | `My Team` |
| `APP_SHORT_DESCRIPTION` | Short description used when the app is first registered. | |
| `APP_LONG_DESCRIPTION` | Long description used when the app is first registered. | |
| `APP_VERSION_ARCHITECTURES` | Comma-separated target architectures. | `x86_64,arm64,armv7` |

Supported architecture values map to Docker platforms as follows: `x86_64` → `linux/amd64`, `arm64` → `linux/arm64`, `armv7` → `linux/arm/v7`. Unrecognized values are ignored; if none remain, the workflow falls back to `x86_64`.

### Repository secrets

Set these under **Settings → Secrets and variables → Actions → Secrets**:

| Secret | Description |
|---|---|
| `REGISTRY_USERNAME` | Registry login username. |
| `REGISTRY_PASSWORD` | Registry login password or token. |

### Environment variables

Defined per GitHub environment (typically `development` and `production`). The shipped workflow targets the `production` environment.

| Variable | Description | Example (production) |
|---|---|---|
| `BARBARA_API_URL` | Barbara API base URL. | `https://prod.bap.barbara.tech` |
| `BARBARA_AUTH_URL` | Keycloak base URL. | `https://prod.auth.barbara.tech` |
| `BARBARA_KEYCLOAK_REALM` | Keycloak realm. | `bbr_prod` |
| `BARBARA_KEYCLOAK_CLIENT_ID` | Keycloak client ID. | |
| `BARBARA_KEYCLOAK_USER_EMAIL` | User email used for token requests. | |
| `VERIFY_TIMEOUT_SECONDS` | Max seconds to wait for deployment health. | `300` |
| `VERIFY_INTERVAL_SECONDS` | Poll interval during verification. | `15` |

### Environment secrets

| Secret | Description |
|---|---|
| `BARBARA_KEYCLOAK_CLIENT_SECRET` | Keycloak client secret. |
| `BARBARA_KEYCLOAK_USER_PASSWORD` | Keycloak user password. |

:::note[Barbara API credentials]

The Keycloak client ID and secret are issued by Barbara as part of an **Enterprise license**. Contact the [Barbara support team](mailto:support@barbara.tech) if you do not have them yet.

:::

## Declare your deployment targets

`deployment-targets.json` at the repo root tells the workflow which devices and groups should receive each new version:

```json
{
  "devices": ["device-a", "device-b"],
  "groups": ["group-a"]
}
```

Resolution rules:

* `devices` entries are matched against `deviceName` in Barbara.
* `groups` entries are matched against `name` in Barbara; every device in a matched group is resolved.
* Devices from both lists are deduplicated by id.
* If any declared device or group does not exist, the pipeline fails **before** building the Docker image.
* After successful validation, the job uploads `dist/resolved-deployment-targets.json` as a workflow artifact for diagnostics.

:::warning

Empty `devices` and `groups` arrays are accepted but the deploy and verify steps will skip with `"status": "skipped"` — no version will reach a device. Always declare at least one target before tagging a release.

:::

## Trigger a release

Pushing a `v*` tag is the only event the workflow listens for. The version published to Barbara and the image tag are both derived from the tag name (`v0.2.0` → version `0.2.0`):

```bash
git tag v0.2.0
git push --tags
```

At runtime, the app combines the semver version with the short commit SHA injected at build time:

```
0.2.0+17a0484
```

Hit any running instance to confirm:

```bash
curl http://<device-ip>:8080/
# → Everything works fine, version 0.2.0+17a0484
```

This makes every container traceable to an exact source commit and CI build.

## The release artifact

The `.zip` uploaded to Barbara contains a single file — a `docker-compose.yaml` that pins the immutable `<sha>`-tagged image built by CI:

```yaml
services:
  sample-barbara-app:
    container_name: sample-barbara-app
    image: bdr.barbara.tech/public/github-actions-sample:17a0484
```

:::warning

Do not substitute a locally rebuilt image for the CI-built one. Only the image built by the workflow carries the embedded build metadata (semver version + short SHA) that powers traceability and rollback.

:::

## Verify and roll back

After deployment, `scripts/verify_deployment.py` polls each target device for up to `VERIFY_TIMEOUT_SECONDS` (default in the example: `300`), at `VERIFY_INTERVAL_SECONDS` intervals (default: `15`). For each device it:

1. Waits until the new image reference is reported as running.
2. Polls the workload's health status until it reports healthy.

If any device fails verification within the timeout window, the script performs a rollback:

* If a previous version exists in Barbara, it is redeployed to every target device.
* If no previous version exists, the workload is removed from every target device.
* The failed version is then deleted from the Barbara application's version list (retried for up to 5 minutes to absorb transient API errors).

The GitHub release is only created if verification succeeds — a failed deployment never produces a release artifact on GitHub.

## Adapt the sample to your own app

The sample is structured so that almost everything app-specific is contained in `app/`, `Dockerfile`, and `docker-compose.yaml`. To turn it into a pipeline for your own application:

1. Replace `app/` with your codebase and update the `Dockerfile` accordingly.
2. Update `docker-compose.yaml` with your service name and any volumes, devices, or [App Config / Secrets](/platform/workload-config/app-config-types/) your workload needs.
3. Bump the `APP_NAME` and `IMAGE_NAME` repository variables to match your app and registry image.
4. Edit `deployment-targets.json` to point at the real device or group names in your Barbara organization.
5. Push a `v*` tag and watch the workflow run.

Keep the `scripts/` folder and the workflow as-is — they are designed to be reusable across apps and to remain valid as the Barbara API evolves.

## Summary

The `barbara_github_actions_sample` repository is a working blueprint for a GitOps-style release pipeline against Barbara: tag a commit, and a single workflow tests, builds, registers, deploys, verifies, and rolls back if needed. Replace the demo app with your own and you have a reusable CI/CD layer for any Barbara-deployable Docker workload.
