Rust 実践講座 #8 配布 — crates.io への公開と GitHub Releases の自動化で完結

読了 4分

最終回です。ツールは完成し(第 1〜5 回)、テストが守っていて(第 6 回)、どのプラットフォーム向けのバイナリも作れます(第 7 回)。残っているのは世に出すことで、道は 2 本あります。Rust 開発者のための crates.io と、Rust を持たない利用者のための GitHub Releases です。

crates.io — cargo install の世界 #

crates.io は基礎第 9 回で依存関係を取ってきたあのレジストリで、公開も同じ場所に行います。まず Cargo.toml のメタデータを埋めます。

Cargo.toml
[package]
name = "loglens"
version = "0.1.0"
edition = "2024"
description = "アクセスログの統計・上位パス・エラー抽出 CLI"
license = "MIT OR Apache-2.0"
repository = "https://github.com/example/loglens"
keywords = ["log", "cli", "nginx"]
categories = ["command-line-utilities"]

descriptionlicense は公開の必須項目です。ライセンスの MIT OR Apache-2.0 という二重表記は Rust エコシステムの慣例的な既定値で、特別な事情がなければ従うのが無難です。公開の手順はリハーサルからです。

公開
cargo publish --dry-run   # パッケージングと検証のみ
cargo publish             # 実際に公開 (crates.io へのログインが必要)

公開前に知っておくべき規則が 1 つあります。crates.io のバージョンは永続的です。 削除も上書きもなく、問題のあるバージョンは cargo yank で「新規利用の遮断」の印を付けられるだけです(すでに lock ファイルで固定した利用者は引き続き取得できます。依存グラフを壊さないための設計です)。間違えたバージョンは直して次のバージョンを上げるのが正解で、だからこそ dry-run がリハーサルとして意味を持ちます。公開が終われば、利用者の体験は 1 行です。

インストール
cargo install loglens

利用者の機械で release ビルドが実行され、~/.cargo/bin に入ります。Python パッケージング編で見た PyPI への公開と同じ構図ですが、仮想環境やランタイムのバージョンの心配がないのがコンパイル言語の利点です。

GitHub Releases — Rust のない利用者へ #

cargo install は利用者に Rust ツールチェーンを要求します。サーバー管理者に「まず rustup を入れてください」とは言えないので、完成済みバイナリをダウンロードする経路が必要です。その慣例の置き場所が GitHub Releases で、第 7 回で作ったターゲット一覧(Linux musl、Mac 2 種、Windows)がここに上がるファイルです。

手で 4 回ビルドしてアップロードすることもできますが、リリースのたびに繰り返す作業は自動化の対象です。GitHub Actions 講座第 4 回で扱ったマトリックスが、まさにこの問題の道具です。

.github/workflows/release.yml
# .github/workflows/release.yml (中核部)
on:
  push:
    tags: ["v*"]

jobs:
  build:
    strategy:
      matrix:
        include:
          - { os: ubuntu-latest,  target: x86_64-unknown-linux-musl }
          - { os: macos-latest,   target: aarch64-apple-darwin }
          - { os: macos-latest,   target: x86_64-apple-darwin }
          - { os: windows-latest, target: x86_64-pc-windows-msvc }
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - run: rustup target add ${{ matrix.target }}
      - run: cargo test
      - run: cargo build --release --target ${{ matrix.target }}
      # 以降: 成果物を圧縮 → リリースへアップロード

読み方はこうです。v0.1.0 のようなタグをプッシュするとワークフローが起動し、マトリックスの 4 つの組み合わせがそれぞれの OS ランナーで並列にビルドされます。第 7 回で予告したとおり各 OS が自分のぶんをビルドするので、クロスコンパイルのリンカ問題は Linux musl ターゲット程度に縮みます。cargo test がビルドの前に立っているのも偶然ではありません。第 6 回のテストが 3 つの OS すべてで通らなければリリースは作られない、タグ 1 つで検証から配布までつながるパイプラインです。

シリーズを終えて #

8 回の旅程をツールの履歴書として要約するとこうなります。インターフェースが型として宣言されていて(clap)、失敗が設計されていて(anyhow・thiserror)、メモリ使用が予測可能で(BufReader ストリーミング)、コアを全部使い(rayon)、動作がテストで文書化されていて(assert_cmd)、どこでも動く単一バイナリで(musl)、タグ 1 つで自動配布されます(Actions)。各回の決定が積み重なって、「動くコード」が「人に勧められるツール」になりました。

基礎講座が文法の背骨だったなら、この講座は筋肉でした。次の一歩としては、自分の業務の繰り返し作業を 1 つ、同じ骨格(clap → エラー設計 → コアロジック → テスト → 配布)でツール化してみることをお勧めします。2 つ目のツールは驚くほど速く出来上がるはずです。

まとめ #

  • crates.io への公開はメタデータ(description、license 必須)→ --dry-run のリハーサル → cargo publish の順です。公開されたバージョンは永続的で、問題のあるバージョンは yank で新規利用だけ遮断します。
  • cargo install loglens が Rust 開発者向けのインストール体験です。ランタイムの心配がないのがコンパイル言語の利点です。
  • Rust のない利用者には GitHub Releases に完成済みバイナリを置きます。第 7 回のターゲット一覧がそのまま配布ファイルの一覧です。
  • タグのプッシュ → マトリックスビルド → リリースへのアップロードが自動化の骨格です。各 OS ランナーがそれぞれビルドするので、クロスコンパイルの負担も減ります。
  • テストがビルドの前に立つパイプラインが完成形です。タグ 1 つで検証から配布まで。実践講座はここまでです。
X