A CLI tool that generates highly-optimized CI configuration files. Reduce duplication, avoid vendor lock-in, and make your CI configuration far more maintainable.
This tool can be used to build both static config and dynamic config for CircleCI. The CLI includes a file hashing feature that can be used during the initial setup workflow to skip jobs when no files have changed.
- First-class support for caching with configurable backends
- Automatically adds OS, version, and architecture to cache keys
- First-class support for running jobs on multiple architectures and self-hosted runners
- Automatic git checkout with extra caching support for self-hosted runners
- Intelligent job skipping based on file changes
- Automatic job dependencies with cache restoration
- Written in Rust for performance
- Powerful templating engine (Tera)
DocSpring's CI config has become very complex over time. We started by implementing highly efficient caching optimizations that skip jobs entirely when a set of source files hasn't changed. We then needed to build multi-architecture Docker images for on-premise deployments (ARM and AMD). So we needed to run our test suite (and all dependent jobs) on both architectures.
Then we started experimenting with self-hosted runners. Our self-hosted runners run in a different country to CircleCI so they need their own local caching for packages. They also need a cache of our git repo since cloning the entire repo from GitHub each time is very slow. I wanted to be able to change one line in our config to send jobs to our self-hosted runners and automatically use the right caching config.
We had built our own internal CI config generation system in Ruby, but it had started to become very unmaintainable as we added all of these features. It was time to rewrite it in Rust and share our work with other companies who have similar needs.
cigen
simplifies CI/CD configuration management by:
- Generating CI pipeline configurations from reusable templates
- Integrating with Nx monorepo tooling to understand project dependencies
- Supporting multiple CI providers (starting with CircleCI)
- Providing plugin-based architecture for cache backends and CI providers
cigen
is highly opinionated about CI/CD configuration.
We automatically add a highly-optimized git checkout step to the beginning of each job, which includes caching for remote runners. The git checkout step can be skipped for jobs that don't need it.
Most CI providers only support caching as a second-class feature - something you add as a "step" during your job. cigen
makes caching an integral part of your CI config. Every job MUST provide a list of file patterns. If none of those files have changed, the job is skipped and the existing cache is used. We inject all of the caching steps automatically.
CI providers often solve the same problem in different ways. e.g. to avoid duplication in your config, GitHub actions has "reusable workflows" while CircleCI supports "commands".
cigen
takes the best ideas from each provider and supports our own set of core features. You write your config once, then we compile it to use your chosen CI provider's native features. This avoids vendor lock-in and makes it easier to migrate to other CI providers.
You can still write a step that uses GitHub's "Actions" or CircleCI's "orbs". (We'll just raise a validation error if you try to use an "orb" on GitHub actions.)
Clone the repository:
git clone https://github.com/DocSpring/cigen.git
cd cigen
Prerequisites:
- Rust (will automatically use 1.88.0 via
rust-toolchain.toml
) - Git
-
Run the setup script (installs git hooks and checks your environment):
./scripts/setup.sh
-
Build the project:
cargo build
context7
- https://github.com/upstash/context7
- Installed automatically via npx
Run all tests:
cargo test
Run tests with output:
cargo test -- --nocapture
Debug build:
cargo build
Release build (optimized):
cargo build --release
From source:
cargo run -- --help
After building:
./target/debug/cigen --help
Or for release build:
./target/release/cigen --help
Format code:
cargo fmt
Run linter:
cargo clippy
Check code without building:
cargo check
Run with verbose logging:
RUST_LOG=debug cargo run
This project uses Lefthook for git hooks. The setup script installs it automatically, but you can also install it manually:
# macOS
brew install lefthook
# Or download directly
curl -sSL https://github.com/evilmartians/lefthook/releases/latest/download/lefthook_$(uname -s)_$(uname -m) -o /usr/local/bin/lefthook
chmod +x /usr/local/bin/lefthook
The git hooks will:
- pre-commit: Run
cargo fmt --check
,cargo clippy
, andcargo test
- pre-push: Run full checks including
cargo check
To skip hooks temporarily: git commit --no-verify
cigen/
├── src/
│ ├── main.rs # CLI entry point
│ └── lib.rs # Library code
├── tests/
│ └── integration_test.rs # Integration tests
├── scripts/
│ └── setup.sh # Developer setup script
├── .cigen/ # Templates and configuration (future)
├── Cargo.toml # Project dependencies
├── rust-toolchain.toml # Rust version specification
├── .rustfmt.toml # Code formatting rules
├── .clippy.toml # Linting configuration
├── lefthook.yml # Git hooks configuration
└── README.md # This file
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Run tests and ensure they pass (
cargo test
) - Format your code (
cargo fmt
) - Run clippy and fix any warnings (
cargo clippy
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and feature requests, please use the GitHub issue tracker.