# Anodizer
A Rust-native release automation tool. The same declarative, config-driven release pipeline that [GoReleaser](https://goreleaser.com/) provides for Go — built for Rust.
Anodizer reads a declarative config file and executes a full release pipeline: build, archive, checksum, changelog, sign, release, publish, and announce — all from a single `anodizer release` command.
Written by [Claude](https://claude.ai); maintained by us.
See [What works (with proof)](https://tj-smith47.github.io/anodizer/dogfooding/) for a per-feature status — every "live" claim links to a real published artifact you can verify yourself.
## Features
**Build**
- Cross-platform builds via `cargo-zigbuild`, `cross`, or native `cargo build`
- Per-build hooks (pre/post), environment variables, feature flags, and target overrides
- UPX binary compression with per-target filtering
- Workspace support with per-crate independent release cadences
**Package**
- Archives in tar.gz, tar.xz, tar.zst, zip, gz, or raw binary format with OS-specific overrides
- Linux packages (.deb, .rpm, .apk, .archlinux, .ipk) via nFPM with full lifecycle scripts
- Snapcraft snaps with prime-dir architecture
- macOS DMG disk images and PKG installers
- Windows MSI and NSIS installers
- Flatpak bundles
- Makeself self-extracting archives
- Source RPMs (.src.rpm)
- Source archives with file filtering
- SBOM generation (CycloneDX/SPDX)
- Checksums with SHA-256, SHA-512, SHA3, BLAKE2b, BLAKE2s, BLAKE3, CRC32, MD5, and more
**Sign**
- GPG and cosign signing for binaries, archives, checksums, Docker images, and SBOMs
- Multiple independent signing configurations
- Conditional signing via template expressions
**Publish**
- GitHub/GitLab/Gitea Releases with asset uploads, draft/prerelease detection, header/footer templates
- crates.io with dependency-aware ordering and index polling
- Homebrew formula and cask generation
- Scoop manifest generation
- Chocolatey package generation
- Winget manifest generation
- AUR PKGBUILD and .SRCINFO generation
- Krew plugin manifest generation
- Nix derivation generation
- MCP registry server-manifest publishing (Model Context Protocol)
- npm package publishing
- Docker multi-arch images via `docker buildx`
- Blob storage uploads (S3, GCS, Azure)
- Artifactory, Cloudsmith, Fury, Docker Hub
- Custom publisher commands
**Announce**
- Discord, Slack, Telegram, Teams, Mattermost
- Email, Reddit, Twitter/X, Mastodon, Bluesky, LinkedIn
- OpenCollective, Discourse
- Generic webhooks with custom headers and templates
**Advanced**
- Tera templates (Jinja2-like) with GoReleaser-compatible `{{ .Field }}` syntax
- Nightly builds with date-based versioning
- Config includes for shared configuration
- Split/merge CI for fan-out parallel builds
- Monorepo support with independent workspaces
- Auto-tagging from commit message directives
- Reproducible builds with `mod_timestamp` and `builds_info`
- JSON Schema for editor autocomplete and validation
## Installation
### Homebrew (macOS/Linux)
```bash
brew install tj-smith47/tap/anodizer
```
### Cargo
```bash
cargo install anodizer
```
### From source
```bash
git clone https://github.com/tj-smith47/anodizer.git
cd anodizer
cargo install --path crates/cli
```
## Quick Start
```bash
# Generate a starter config from your Cargo workspace
anodizer init > .anodizer.yaml
# Validate your config
anodizer check
# Check that required tools are available
anodizer healthcheck
# Build a snapshot (no publishing)
anodizer release --snapshot
# Dry run (full pipeline, no side effects)
anodizer release --dry-run
# Create a tag and release
git tag -a v0.1.0 -m "v0.1.0"
git push origin v0.1.0
```
For CI-based releases, set `GITHUB_TOKEN` (or `ANODIZER_GITHUB_TOKEN`) as a secret — the release pipeline picks it up automatically.
## Configuration
Anodizer uses `.anodizer.yaml` (or `.anodizer.toml`) in your project root. Add a schema comment for editor autocomplete:
```yaml
# yaml-language-server: $schema=https://tj-smith47.github.io/anodizer/schema.json
project_name: myapp
defaults:
targets:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-pc-windows-msvc
cross: auto
crates:
- name: myapp
path: "."
tag_template: "v{{ Version }}"
builds:
- binary: myapp
archives:
- name_template: "{{ ProjectName }}-{{ Version }}-{{ Os }}-{{ Arch }}"
files: [LICENSE, README.md]
release:
github:
owner: myorg
name: myapp
publish:
crates:
enabled: true
homebrew:
tap:
owner: myorg
name: homebrew-tap
```
See the [full configuration reference](https://tj-smith47.github.io/anodizer/docs/reference/configuration/) and the [template reference](https://tj-smith47.github.io/anodizer/docs/general/templates/) for all available fields, variables, and filters.
## GitHub Actions
```yaml
name: Release
on:
push:
tags: ["v*"]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- name: Install anodizer
run: cargo install anodizer
- name: Release
run: anodizer release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## CLI Reference
### Commands
```
anodizer release Full release pipeline
anodizer build Build binaries only (snapshot mode)
anodizer check Validate configuration
anodizer init Generate starter config
anodizer changelog Generate changelog only
anodizer completion <shell> Shell completions (bash/zsh/fish/powershell)
anodizer healthcheck Check external tool availability
anodizer man Generate man pages
anodizer jsonschema Output JSON Schema for .anodizer.yaml
anodizer tag Auto-tag from commit directives
anodizer publish Run publish stages from completed dist/
anodizer announce Run announce stage from completed dist/
anodizer continue Merge split build artifacts and resume pipeline
```
### Global Flags
```
-f, --config <path> Path to config file (overrides auto-detection)
--verbose Enable verbose output
--debug Enable debug output
-q, --quiet Suppress non-error output
```
### Release Flags
```
--crate <name> Release a specific crate (repeatable)
--all Release all crates with unreleased changes
--force Force release even without changes
--snapshot Build without publishing
--nightly Nightly release with date-based version
--dry-run Full pipeline, no side effects
--clean Remove dist/ directory first
--skip=<stages> Skip stages (comma-separated)
--token <token> GitHub token (overrides env vars)
--timeout <duration> Pipeline timeout (default: 60m)
-p, --parallelism <n> Max parallel build jobs (default: CPU count)
--auto-snapshot Auto-enable snapshot if repo is dirty
--single-target Build only for the host target triple
--split Fan-out: build only, output artifacts JSON
--merge Fan-in: merge split artifacts, run post-build
--draft Set the release as a draft
--release-notes <path> Custom release notes file
--release-header <path> Custom release header file
--release-footer <path> Custom release footer file
--workspace <name> Release a specific monorepo workspace
--fail-fast Abort on first publish error
```
## Documentation
Full documentation is available at **[tj-smith47.github.io/anodizer](https://tj-smith47.github.io/anodizer/)**.
## License
MIT