A CLI tool for automating CI tasks across Charmed Operator repositories
Project description
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"
- All file paths are relative to the repo root
- Paths can use
dotandbracketnotation for navigating YAML/JSON
🧪 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.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file charmed_analytics_ci-1.1.0.tar.gz.
File metadata
- Download URL: charmed_analytics_ci-1.1.0.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cbf41a2fd6b863a4620d970a4aa7b8d4f8c22a3a315ddeefd362742510948cc8
|
|
| MD5 |
bb9e3d6d504db9e01988baec6660a40e
|
|
| BLAKE2b-256 |
038bd3d199c5d0e68b2c711dae58bf8335ba4f6161a41c4948ee3fd30d53fe99
|
File details
Details for the file charmed_analytics_ci-1.1.0-py3-none-any.whl.
File metadata
- Download URL: charmed_analytics_ci-1.1.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8eca7f7feb3ae8da463282b8372568118e6a452d7c9efe1896b8f3ce7a2615a4
|
|
| MD5 |
0388158a9c9163bcd4b98f5f152032e5
|
|
| BLAKE2b-256 |
2900a7958d99e4a60a717d492845512322a4f1abf198501ed4b3398cd1d3f86a
|