anodizer 0.4.0

A Rust-native release automation tool inspired by GoReleaser
Documentation

anodizer

A Rust-native release pipeline — GoReleaser parity, signed and deterministic by default.

CI Release Docs Crates.io License: MIT

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. The same declarative, config-driven release pipeline that GoReleaser provides for Go — built for Rust.

Written by Claude; maintained by us.

See What works (with proof) 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)

brew install tj-smith47/tap/anodizer

Cargo

cargo install anodizer

From source

git clone https://github.com/tj-smith47/anodizer.git
cd anodizer
cargo install --path crates/cli

Quick Start

# 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

# Auto-tag from commit directives
# (Conventional Commits: feat: → minor, fix: → patch, BREAKING CHANGE: → major)
anodizer tag --dry-run   # preview what tag would be created
anodizer tag             # create + push the tag, which triggers the release workflow

# Or force a specific tag value:
anodizer tag --custom-tag 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-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:
      cargo: {}
      homebrew:
        repository:
          owner: myorg
          name: homebrew-tap

See the full configuration reference and the template reference for all available fields, variables, and filters.

Real-world adoption: cfgd

cfgd — declarative, GitOps-style machine configuration management — is anodizer's first real-world adopter and dogfoods every shipped publisher. It's a 4-crate workspace (shared lib + CLI + Kubernetes operator + CSI driver) that ships to crates.io (dependency-aware ordering), GitHub Releases, Homebrew, Scoop, Chocolatey, Winget, the Snap Store, Krew, GHCR, and via cargo binstall — all from one .anodizer.yaml and one tag push.

A condensed slice of cfgd's .anodizer.yaml:

workspaces:
  - name: cfgd-core
    crates:
      - name: cfgd-core
        tag_template: "core-v{{ Version }}"
        version_sync: { enabled: true, mode: cargo }

  - name: cfgd
    crates:
      - name: cfgd
        depends_on: [cfgd-core]
        version_sync: { enabled: true, mode: cargo }
        universal_binaries:
          - name_template: "{{ ProjectName }}"
            replace: false
        binstall:
          enabled: true
          pkg_url: "https://github.com/tj-smith47/cfgd/releases/download/v{{ Version }}/cfgd-{{ Version }}-{ target }.tar.gz"
          pkg_fmt: tgz
  # ... cfgd-operator, cfgd-csi

Every cell of What works (with proof) links to a real published cfgd artifact for the feature in question — that's the verification surface.

GitHub Actions

Anodizer ships a first-party action, tj-smith47/anodizer-action, which is what this repo dogfoods in its own release.yml:

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: Release
        uses: tj-smith47/anodizer-action@v1
        with:
          version: latest
          auto-install: true   # auto-detect nfpm/makeself/snapcraft/cosign/etc from .anodizer.yaml
          args: release --clean
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

For split/merge fan-out, GPG key import, registry login, and per-platform variants, see anodizer-action and the live .github/workflows/release.yml in this repo.

CLI Reference

anodizer release       Full release pipeline (--snapshot, --dry-run, --split/--merge, --publish-only, --rollback-only)
anodizer tag           Auto-tag from commit directives
anodizer check         Validate configuration + run determinism harness
anodizer init          Generate starter .anodizer.yaml
anodizer healthcheck   Probe external tools (nfpm, cosign, ...)

Full reference: anodizer --help or the docs site.

Documentation

Full documentation is available at tj-smith47.github.io/anodizer.

Operator guides:

License

MIT