19 releases (12 breaking)
| 0.13.0 | Apr 19, 2026 |
|---|---|
| 0.11.1 | Apr 2, 2026 |
| 0.11.0 | Mar 29, 2026 |
| 0.7.1 | Dec 9, 2025 |
| 0.1.0 | Sep 7, 2024 |
#234 in Build Utils
359 downloads per month
Used in cicero_cli
68KB
981 lines
Cicero
Cicero helps you implement a CLI for the CI needs of your Rust project.
You implement this CLI in Rust to benefit from its flexibility and familiarity, while Cicero provides a framework that simplifies common patterns and solves the hard parts that you really shouldn't write a custom solution for.
Usage
Below is a working example for building a distribution archive. The modules would be put into separate files.
mod main_rs {
use clap::Parser;
use crate::distribution;
#[derive(Parser)]
enum Cli {
Distribution(distribution::DistributionCli),
}
cicero::workspace!(); //collect information about your workspace crates
fn main() -> cicero::Result<()> {
cicero::init::tracing().init(); //set up logging
match Cli::parse() { //can add multiple subcommands/workflows
Cli::Distribution(cli) => cli.run(),
}
}
}
mod distribution {
use std::{fs, path::Path};
use cicero::distribution::{bundle::zip::ZipBundler, Distribution, build::{ExecutableBuilder, target}};
use cicero::path::repo_path;
use crate::main_rs::workspace;
#[derive(clap::Args)]
pub struct DistributionCli;
impl DistributionCli {
pub fn run(self) -> cicero::Result<()> {
let distribution = Distribution::new("myproject")?;
distribution
.add_file_from_path(
"README.md", //include into distribution as "README.md"
repo_path!("README.md") //load from path relative to repository root (compile-safe!)
)?
.add_executable(
"myproject_ci", //include as "myproject_ci", or "myproject_ci.exe" when targeting Windows
ExecutableBuilder::new(
workspace::package::ci //crate name from your workspace, as collected by `cicero::workspace!()` above
)
.target(
// `target` module provides compile-time access to targets supported by the Rust compiler.
// Can also parse from the CLI via `Target::from_str()`.
target::x86_64_unknown_linux_gnu
)
)?;
distribution
.dir("doc")? //include the following under a subdirectory "doc/"
.add_all(|dir| build_doc(dir))?;
let path = distribution.bundle(ZipBundler)?;
eprintln!("Placed distribution into {path:?}.");
Ok(())
}
}
use cicero::commands::{Cli, Crate};
use cicero::command_exit_ok::CommandExitOk;
pub static MDBOOK: Cli = Crate::new("mdbook").into_cli(); //defines installation instructions for a CLI tool
pub fn build_doc(out_dir: &Path) -> cicero::Result<()> {
MDBOOK.command() //triggers installation and provides std::process:Command object
.arg("build")
.arg("--dest-dir").arg(out_dir) //write files into distribution directory
.current_dir(repo_path!("doc/"))
.status_exit_ok()?; //runs command like `.status()`, but returns error when status code != 0
Ok(())
}
}
# //only needed for running this example in automated tests
# fn main() -> cicero::Result<()> { distribution::DistributionCli.run() }
In a codebase with Cicero set up, you would run this example with cargo ci distribution.
It will then build a ZIP archive that contains these files:
myproject
├── README.md
├── myproject_ci (executable)
└── doc
└── ...
Getting Started
Cicero uses a file structure akin to the cargo-xtask pattern. To set it up, you can use the following commands:
cargo install cicero_cli
cicero init #run in your repository
cargo ci hello #runs the 'hello' workflow added by the default template
You can find usage examples in the Cicero repository: https://codeberg.org/trem/cicero/src/branch/main/examples
Changelog
The changelog is available here: https://codeberg.org/trem/cicero/src/branch/main/CHANGELOG.md
Dependencies
~6–14MB
~206K SLoC