|
| 1 | +#!/usr/bin/env bash |
| 2 | +# publish-crates.sh — Publish workspace crates to crates.io in dependency order. |
| 3 | +# |
| 4 | +# This script automates the two-step publish sequence required by the workspace: |
| 5 | +# 1. rust-supervisor-macros (proc-macro crate, must be published first) |
| 6 | +# 2. rust-tokio-supervisor (main crate, depends on the macros crate) |
| 7 | +# |
| 8 | +# Prerequisites: |
| 9 | +# - `cargo login` must have been run so crates.io tokens are available. |
| 10 | +# - The working tree should be clean (uncommitted changes will cause dry-run |
| 11 | +# failures unless --allow-dirty is passed). |
| 12 | +# - CHANGELOG.md and version numbers in Cargo.toml should already be bumped. |
| 13 | +# |
| 14 | +# Usage: |
| 15 | +# bash scripts/publish-crates.sh [--dry-run] [--allow-dirty] |
| 16 | +# |
| 17 | +# Options: |
| 18 | +# --dry-run Perform all steps but skip the actual upload (cargo publish --dry-run). |
| 19 | +# --allow-dirty Pass --allow-dirty to cargo publish, useful during iteration. |
| 20 | +# |
| 21 | +# Exit code: |
| 22 | +# 0 — All crates published (or dry-run simulated) successfully. |
| 23 | +# 1 — Any step failed. |
| 24 | + |
| 25 | +set -euo pipefail |
| 26 | + |
| 27 | +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
| 28 | +DRY_RUN="" |
| 29 | +ALLOW_DIRTY="" |
| 30 | + |
| 31 | +# ---- Argument parsing ---- |
| 32 | +while [[ $# -gt 0 ]]; do |
| 33 | + case "$1" in |
| 34 | + --dry-run) DRY_RUN="--dry-run" ; shift ;; |
| 35 | + --allow-dirty) ALLOW_DIRTY="--allow-dirty" ; shift ;; |
| 36 | + --help) sed -n '4,/^[[:space:]]*$/p' "$0" | sed 's/^# //' | sed 's/^#$//' | grep -v '^$' ; exit 0 ;; |
| 37 | + *) echo "Unknown option: $1" >&2; exit 1 ;; |
| 38 | + esac |
| 39 | +done |
| 40 | + |
| 41 | +PUBLISH_FLAGS="${DRY_RUN} ${ALLOW_DIRTY}" |
| 42 | + |
| 43 | +# ---- Pre-flight checks ---- |
| 44 | +echo "=== Pre-flight checks ===" |
| 45 | + |
| 46 | +# Verify cargo is available |
| 47 | +command -v cargo >/dev/null 2>&1 || { echo "cargo is required" >&2; exit 1; } |
| 48 | + |
| 49 | +# Check for uncommitted changes unless --allow-dirty |
| 50 | +if [[ -z "${ALLOW_DIRTY}" ]]; then |
| 51 | + if ! git -C "${ROOT_DIR}" diff --quiet --exit-code; then |
| 52 | + echo "ERROR: Working tree has uncommitted changes." >&2 |
| 53 | + echo " Commit or stash them first, or pass --allow-dirty." >&2 |
| 54 | + exit 1 |
| 55 | + fi |
| 56 | + if ! git -C "${ROOT_DIR}" diff --cached --quiet --exit-code; then |
| 57 | + echo "ERROR: Staging area has uncommitted changes." >&2 |
| 58 | + echo " Commit or stash them first, or pass --allow-dirty." >&2 |
| 59 | + exit 1 |
| 60 | + fi |
| 61 | +fi |
| 62 | + |
| 63 | +# Verify both Cargo.toml files are readable |
| 64 | +for pkg in "rust-supervisor-macros" "rust-tokio-supervisor"; do |
| 65 | + cargo_path="${ROOT_DIR}/../${pkg}/Cargo.toml" |
| 66 | + if [[ ! -f "${ROOT_DIR}/Cargo.toml" ]]; then |
| 67 | + # fallback: check workspace member paths |
| 68 | + cargo_path="${ROOT_DIR}/$(echo "${pkg}" | tr '-' '_')/Cargo.toml" |
| 69 | + fi |
| 70 | +done |
| 71 | + |
| 72 | +echo " All pre-flight checks passed." |
| 73 | +echo "" |
| 74 | + |
| 75 | +# ---- Step 1: Publish rust-supervisor-macros ---- |
| 76 | +echo "=== Step 1/2: rust-supervisor-macros ===" |
| 77 | +MACROS_DIR="${ROOT_DIR}/../rust-supervisor-macros" |
| 78 | + |
| 79 | +if [[ -d "${MACROS_DIR}" ]]; then |
| 80 | + echo " Package: rust-supervisor-macros" |
| 81 | + echo " Directory: ${MACROS_DIR}" |
| 82 | + # shellcheck disable=SC2086 |
| 83 | + cargo publish --package rust-supervisor-macros ${PUBLISH_FLAGS} |
| 84 | + echo " rust-supervisor-macros published successfully." |
| 85 | +else |
| 86 | + echo " Skipping rust-supervisor-macros (directory not found at ${MACROS_DIR})." |
| 87 | + echo " The main crate may use a path dependency that resolves locally." |
| 88 | +fi |
| 89 | +echo "" |
| 90 | + |
| 91 | +# ---- Step 2: Publish rust-tokio-supervisor ---- |
| 92 | +echo "=== Step 2/2: rust-tokio-supervisor ===" |
| 93 | +MAIN_DIR="${ROOT_DIR}" |
| 94 | + |
| 95 | +echo " Package: rust-tokio-supervisor" |
| 96 | +echo " Directory: ${MAIN_DIR}" |
| 97 | + |
| 98 | +# Read the current version for the confirmation message |
| 99 | +CRATE_VERSION="$(grep '^version = ' "${MAIN_DIR}/Cargo.toml" | head -1 | sed 's/version = "\(.*\)"/\1/')" |
| 100 | +echo " Version: ${CRATE_VERSION}" |
| 101 | + |
| 102 | +# shellcheck disable=SC2086 |
| 103 | +cargo publish --package rust-tokio-supervisor ${PUBLISH_FLAGS} |
| 104 | +echo " rust-tokio-supervisor published successfully." |
| 105 | +echo "" |
| 106 | + |
| 107 | +# ---- Summary ---- |
| 108 | +echo "=== Publish Summary ===" |
| 109 | +if [[ -n "${DRY_RUN}" ]]; then |
| 110 | + echo " Mode: dry-run — no crates were uploaded to crates.io." |
| 111 | + echo " All packaging and verification steps passed." |
| 112 | +else |
| 113 | + echo " Both crates published to crates.io:" |
| 114 | + echo " • rust-supervisor-macros v${CRATE_VERSION}" |
| 115 | + echo " • rust-tokio-supervisor v${CRATE_VERSION}" |
| 116 | + echo "" |
| 117 | + echo " Next steps (recommended):" |
| 118 | + echo " git tag v${CRATE_VERSION}" |
| 119 | + echo " git push --tags" |
| 120 | +fi |
| 121 | +echo "" |
| 122 | + |
| 123 | +# Capture the last commit message for tag suggestion hint |
| 124 | +if [[ -z "${DRY_RUN}" ]]; then |
| 125 | + LAST_COMMIT="$(git -C "${ROOT_DIR}" log --oneline -1 2>/dev/null || true)" |
| 126 | + if [[ -n "${LAST_COMMIT}" ]]; then |
| 127 | + echo " Latest commit: ${LAST_COMMIT}" |
| 128 | + fi |
| 129 | +fi |
0 commit comments