charmed-analytics-ci
A CLI tool to automate CI-driven integration of updated rock images into consumer Charmed Operator repositories.
This tool is part of Canonical's Charmed Kubeflow stack and enables automated pull request creation after a rock image is built and published. It eliminates manual effort, reduces human error, and supports scalable, reproducible CI/CD pipelines.
✨ Features
- ✅ Automatically clones target charm repositories
- 🔁 Updates image references in YAML or JSON configuration files
- ⚙️ Optionally modifies service-spec fields like
userandcommand - 🔧 Validates metadata schemas for correctness before modification
- 🤖 Opens pull requests with deterministic branches and templated descriptions
- 🔐 Supports GitHub authentication via token or environment variable
- 🔗 Optionally links back to triggering PR
- 📦 Installable via PyPI and usable from CI pipelines
- 🧪 Supports dry-run mode for previewing changes
🚀 Installation
Install from PyPI:
pip install charmed-analytics-ci
Or install for development:
git clone https://github.com/canonical/charmed-analytics-ci.git
cd charmed-analytics-ci
poetry install
🧪 CLI Usage
After installing, the CLI provides a single command:
chaci integrate-rock METADATA_FILE BASE_BRANCH ROCK_IMAGE [OPTIONS]
Example:
export GH_TOKEN="ghp_abc123..." # or pass explicitly with --github-token
chaci integrate-rock rock-ci-metadata.yaml main ghcr.io/canonical/my-rock:1.0.0 --dry-run
Arguments:
| Argument | Description |
|---|---|
METADATA_FILE |
Path to rock-ci-metadata.yaml describing integration targets |
BASE_BRANCH |
Target branch for PRs (e.g. main or develop) |
ROCK_IMAGE |
Full rock image string (e.g. ghcr.io/org/my-rock:1.0.0) |
Options:
| Option | Description |
|---|---|
--github-token |
Optional. GitHub token. Falls back to $GH_TOKEN environment variable if not provided. |
--github-username |
Optional. GitHub username. Defaults to "__token__" if not provided. |
--clone-dir PATH |
Optional. Directory where target repos will be cloned (default: /tmp). |
--dry-run |
Optional. If set, changes are simulated but not committed or pushed. Logs changes to console. |
--triggering-pr URL |
Optional. Link to the PR which triggered this run. Included in the PR body if present. |
📄 rock-ci-metadata.yaml Format
integrations:
- consumer-repository: canonical/my-charm
replace-image:
- file: "metadata.yaml"
path: "resources.my-rock.upstream-source"
- file: "src/images.json"
path: "config.batcher"
service-spec:
- file: "service-spec.json"
user:
path: "containers[0].user"
value: "1001"
command:
path: "containers[0].command[1]"
value: "/start"
registry: "ghcr.io/canonical"
- All file paths are relative to the repo root
- Paths can use
dotandbracketnotation for navigating YAML/JSON registryis optional. It names the container registry the rock is published to, including the host. It is consumed by CI tooling to override its default registry and is ignored bychaci.
🧪 Testing
Unit tests
tox -e unit
🔁 Integration tests
⚠️ These tests interact with a real GitHub repository and require a fine-grained GitHub token with appropriate permissions.
Required GitHub token permissions
The token must be a fine-grained personal access token (PAT) with:
- Repository access: Select the repository you're testing against
- Permissions:
Contents: Read and writePull requests: Read and write
These are needed to:
- Clone the repo
- Push branches
- Open and manage pull requests
Setup and run:
export CHACI_TEST_TOKEN=<your_token>
export CHACI_TEST_REPO="org/repo-name"
export CHACI_TEST_BASE_BRANCH="target-branch"
tox -e integration
The integration tests will:
- Clone the specified repository
- Create a temporary branch and pull request
- Validate the PR contents
- Clean up the branch and PR after execution
🧰 Development & Contributing
This project uses:
To run all checks locally:
tox -e lint,unit,integration
📁 Project Structure
| File | Purpose |
|---|---|
rock_integrator.py |
Core logic for modifying files with images |
git_client.py |
Git and GitHub abstraction for PR workflow |
rock_metadata_handler.py |
Orchestration for multi-repo integration |
rock_ci_metadata_models.py |
Pydantic model for metadata schema validation |
main.py |
CLI entrypoint via click |
templates/pr_body.md.j2 |
Jinja2 template for pull request bodies |
🔒 License
This project is licensed under the Apache 2.0 License.
✍️ Authors
Built by the Canonical Charmed Kubeflow team.
Metadata
Release files for charmed-analytics-ci 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| charmed_analytics_ci-1.3.0.tar.gz | 18.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| charmed_analytics_ci-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.3 kB
Release files / charmed_analytics_ci-1.3.0.tar.gz
| Download URL | charmed_analytics_ci-1.3.0.tar.gz |
|---|---|
| Size | 18.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d50fab62731132dfddb3f9950b7fd0da1fbc37fe396f5574f0a2346d47db6d6c
|
|
BLAKE2b-256 checksum How to use checksums |
cecaa7c2ba5503482ab4665195f4ca6973f977c65a804c6f663cdbac0b2a59e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Release files / charmed_analytics_ci-1.3.0-py3-none-any.whl
| Download URL | charmed_analytics_ci-1.3.0-py3-none-any.whl |
|---|---|
| Size | 20.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
71e5615f54ff9b8732e50e4a2a53305600bd0f0bb9aea061b53877f458ae1489
|
|
BLAKE2b-256 checksum How to use checksums |
764cd348e975052ee23aa468f9954e520579bf1e25fe32e9f692ee90df40b2fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|