Skip to content

publish

publish #4

Workflow file for this run

name: publish
on:
workflow_dispatch:
inputs:
dry_run:
description: "Run cargo publish in dry-run mode"
required: true
default: true
type: boolean
packages:
description: "Comma-separated package list; empty publishes the full workspace"
required: false
default: ""
type: string
skip_published:
description: "Skip versions that already exist on crates.io during a real publish"
required: true
default: true
type: boolean
permissions:
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: publish crates
env:
DRY_RUN: ${{ inputs.dry_run }}
SELECTED_PACKAGES: ${{ inputs.packages }}
SKIP_PUBLISHED: ${{ inputs.skip_published }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: |
set -euo pipefail
ordered_packages=(
aelf-proto
aelf-crypto
aelf-client
aelf-keystore
aelf-contract
aelf-sdk
)
declare -A allowed_packages=()
declare -A requested_packages=()
for pkg in "${ordered_packages[@]}"; do
allowed_packages["$pkg"]=1
done
if [[ -n "${SELECTED_PACKAGES//[[:space:]]/}" ]]; then
IFS=',' read -r -a raw_packages <<< "$SELECTED_PACKAGES"
for raw_pkg in "${raw_packages[@]}"; do
pkg="${raw_pkg//[[:space:]]/}"
if [[ -z "$pkg" ]]; then
continue
fi
if [[ -z "${allowed_packages[$pkg]:-}" ]]; then
echo "::error::Unsupported package '$pkg'. Allowed packages: ${ordered_packages[*]}"
exit 1
fi
requested_packages["$pkg"]=1
done
if [[ "${#requested_packages[@]}" -eq 0 ]]; then
echo "::error::No valid packages were provided."
exit 1
fi
fi
package_selected() {
local pkg="$1"
if [[ "${#requested_packages[@]}" -eq 0 ]]; then
return 0
fi
[[ -n "${requested_packages[$pkg]:-}" ]]
}
crate_version() {
cargo pkgid -p "$1" | sed 's/.*@//'
}
crate_status_code() {
local pkg="$1"
local version="$2"
curl -sS -o /dev/null -w '%{http_code}' "https://crates.io/api/v1/crates/${pkg}/${version}"
}
ensure_crate_visible() {
local pkg="$1"
local version="$2"
local max_attempts=30
local sleep_seconds=10
for ((attempt = 1; attempt <= max_attempts; attempt++)); do
http_code="$(crate_status_code "$pkg" "$version")"
case "$http_code" in
200)
echo "${pkg} ${version} is visible on crates.io."
return 0
;;
404)
echo "Waiting for ${pkg} ${version} to become visible on crates.io (${attempt}/${max_attempts})..."
sleep "$sleep_seconds"
;;
5??)
echo "::error::crates.io returned ${http_code} while checking ${pkg} ${version}."
return 1
;;
*)
echo "::error::Unexpected crates.io status ${http_code} while checking ${pkg} ${version}."
return 1
;;
esac
done
echo "::error::Timed out waiting for ${pkg} ${version} to become visible on crates.io."
return 1
}
if [[ "$DRY_RUN" == "true" && "${#requested_packages[@]}" -eq 0 ]]; then
echo "Running workspace dry-run for the full publish set."
cargo publish --workspace --dry-run --locked
exit 0
fi
if [[ "$DRY_RUN" != "true" && -z "${CARGO_REGISTRY_TOKEN:-}" ]]; then
echo "::error::CARGO_REGISTRY_TOKEN is required when dry_run=false."
exit 1
fi
for pkg in "${ordered_packages[@]}"; do
if ! package_selected "$pkg"; then
continue
fi
version="$(crate_version "$pkg")"
echo "Processing ${pkg} ${version}"
if [[ "$DRY_RUN" == "true" ]]; then
cargo publish -p "$pkg" --dry-run --locked
continue
fi
http_code="$(crate_status_code "$pkg" "$version")"
case "$http_code" in
200)
if [[ "$SKIP_PUBLISHED" == "true" ]]; then
echo "Skipping ${pkg} ${version}; version already exists on crates.io."
continue
fi
echo "::error::${pkg} ${version} already exists on crates.io."
exit 1
;;
404)
;;
5??)
echo "::error::crates.io returned ${http_code} while checking ${pkg} ${version}."
exit 1
;;
*)
echo "::error::Unexpected crates.io status ${http_code} while checking ${pkg} ${version}."
exit 1
;;
esac
cargo publish -p "$pkg" --locked --token "$CARGO_REGISTRY_TOKEN"
ensure_crate_visible "$pkg" "$version"
done