commit 910abf3ec8ef4d9dbdfd06935118ce73db78116f
parent 59024a1d7d24f1aca19eb5402ae57aa56c814a5c
Author: triesap <tyson@radroots.org>
Date: Fri, 10 Apr 2026 01:44:31 +0000
release: remove local publish entrypoints
Diffstat:
8 files changed, 12 insertions(+), 256 deletions(-)
diff --git a/contract/README.md b/contract/README.md
@@ -73,7 +73,7 @@ Primary commands:
- `cargo run -q -p xtask -- sdk validate`
- `cargo run -q -p xtask -- sdk release preflight`
- `./scripts/ci/release_preflight.sh`
-- `./scripts/ci/release_publish_order.sh dry-run`
+- `scripts/release/rr-rs-preflight.sh <release-tag> [crate-list]` from the owning monorepo
## License
diff --git a/contract/release/checklist-0.1.0.md b/contract/release/checklist-0.1.0.md
@@ -4,8 +4,8 @@
- [ ] run `cargo check -q`
- [ ] run `cargo test -q -p xtask`
- [ ] run `./scripts/ci/release_preflight.sh`
-- [ ] run `./scripts/ci/release_publish_order.sh dry-run`
+- [ ] run `scripts/release/rr-rs-preflight.sh <release-tag> [crate-list]` from the owning monorepo
- [ ] confirm crates.io owner and token access for the publish account
-- [ ] run `./scripts/ci/release_publish_order.sh publish`
+- [ ] run `scripts/release/rr-rs-publish.sh <release-tag> [crate-list]` from the owning monorepo
- [ ] verify all publish-set crates are visible on crates.io at the configured release version
- [ ] tag release in git and publish release notes
diff --git a/contract/release/runbook.md b/contract/release/runbook.md
@@ -7,17 +7,18 @@ This runbook applies to the crates listed in `contract/release/publish-set.toml`
## preflight
```bash
-nix run .#release-preflight
+scripts/release/rr-rs-preflight.sh <release-tag> [crate-list]
```
-This command validates:
+Run preflight from the owning monorepo release surface. In `radroots-platform-v1`, the canonical entrypoint is `scripts/release/rr-rs-preflight.sh`.
+
+This validates:
- sdk contract integrity and release policy parity
- required crate coverage at `100/100/100/100`
- publish crate metadata required for crates.io
-The underlying repo-owned entrypoint is `./scripts/ci/release_preflight.sh`.
-External release automation should call the canonical local preflight and must not replace it with forge-specific logic.
+The underlying source-repo preflight lane remains `./scripts/ci/release_preflight.sh`, but publish orchestration is monorepo-owned and must not live in the source checkout.
## release tag
@@ -32,18 +33,18 @@ git tag -a "v$(awk -F '\"' '/^version = / { print $2; exit }' contract/release/p
## publish simulation
```bash
-nix run .#publish-dry-run
+scripts/release/rr-rs-preflight.sh <release-tag> [crate-list]
```
-This runs `cargo publish --dry-run` in release order and reports deferred crates when they depend on earlier crates that are not yet published.
+This runs `cargo publish --dry-run` in release order from the owning monorepo and reports deferred crates when they depend on earlier crates that are not yet published.
## publish
```bash
-nix run .#publish-crates -- --publish
+scripts/release/rr-rs-publish.sh <release-tag> [crate-list]
```
-This publishes in `publish_order` and waits for each crate version to become visible on crates.io before continuing.
+This publishes in `publish_order` from the owning monorepo and waits for each crate version to become visible on crates.io before continuing.
Set `CARGO_REGISTRY_TOKEN` or `CRATES_IO_TOKEN` in the runtime environment before the publish step.
diff --git a/docs/nix.md b/docs/nix.md
@@ -88,8 +88,6 @@ nix run .#coverage-report
nix run .#wasm-builds
nix run .#release-preflight
nix run .#validate-sdk-typescript -- ./sdk-typescript
-nix run .#publish-dry-run
-nix run .#publish-crates -- --dry-run
```
`nix flake check` is intentionally limited to pure surfaces:
@@ -121,7 +119,6 @@ nix run .#release-preflight
- Flakes only see tracked files when the source is treated as a git checkout. If Nix appears to miss a new file, `git add` it first.
- Do not put secrets in `flake.nix`.
-- `publish-crates.sh` reads `CARGO_REGISTRY_TOKEN` or `CRATES_IO_TOKEN` from your runtime environment.
## Deferred Infrastructure
diff --git a/nix/apps.nix b/nix/apps.nix
@@ -98,28 +98,6 @@ in
'';
};
- publish-crates = mkRepoApp {
- name = "publish-crates";
- description = "Publish crates through the workspace release script";
- runtimeInputs = [
- pkgs.nix
- ];
- command = coverageShellExec ''./publish-crates.sh "$@"'';
- env = common.exportCoverageEnv;
- pathPrefix = coveragePath;
- };
-
- publish-dry-run = mkRepoApp {
- name = "publish-dry-run";
- description = "Run a dry-run crates publish through the workspace release script";
- runtimeInputs = [
- pkgs.nix
- ];
- command = coverageShellExec ''./publish-crates.sh --dry-run "$@"'';
- env = common.exportCoverageEnv;
- pathPrefix = coveragePath;
- };
-
release-preflight = mkRepoApp {
name = "release-preflight";
description = "Run release coverage refresh and preflight validation";
diff --git a/nix/common.nix b/nix/common.nix
@@ -20,7 +20,6 @@ let
../Cargo.lock
../Makefile
../README.md
- ../publish-crates.sh
../rust-toolchain.toml
../conformance
../contract
diff --git a/publish-crates.sh b/publish-crates.sh
@@ -1,32 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-cd "$root_dir"
-
-mode="publish"
-case "${1:-}" in
---dry-run)
- mode="dry-run"
- shift
- ;;
---publish)
- mode="publish"
- shift
- ;;
-"") ;;
-*) ;;
-esac
-
-requested="${*:-}"
-
-if [[ $mode == "publish" ]] && [[ -z ${CARGO_REGISTRY_TOKEN:-} ]] && [[ -n ${CRATES_IO_TOKEN:-} ]]; then
- export CARGO_REGISTRY_TOKEN="${CRATES_IO_TOKEN}"
-fi
-
-if [[ $mode == "publish" ]] && [[ -z ${CARGO_REGISTRY_TOKEN:-} ]]; then
- echo "set CARGO_REGISTRY_TOKEN or CRATES_IO_TOKEN before publish"
- exit 1
-fi
-
-exec ./scripts/ci/release_publish_order.sh "$mode" "$requested"
diff --git a/scripts/ci/release_publish_order.sh b/scripts/ci/release_publish_order.sh
@@ -1,187 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
-cd "$root_dir"
-
-mode="${1:-publish}"
-if [[ $mode != "publish" && $mode != "dry-run" ]]; then
- echo "usage: scripts/ci/release_publish_order.sh [publish|dry-run] [crate names]"
- exit 2
-fi
-
-requested_raw="${2:-}"
-requested_raw="${requested_raw//,/ }"
-
-release_version="$(
- awk '
- /^\[release\]/ { in_release = 1; next }
- in_release && /^version = / {
- gsub(/"/, "", $3);
- print $3;
- exit
- }
- ' contract/release/publish-set.toml
-)"
-
-if [[ -z $release_version ]]; then
- echo "failed to resolve release.version from contract/release/publish-set.toml"
- exit 1
-fi
-
-order_file="$(mktemp)"
-
-awk '
- /^\[publish_order\]/ { in_order = 1; next }
- /^\[/ && in_order { exit }
- in_order && /"/ {
- line = $0
- gsub(/[" ,]/, "", line)
- if (length(line) > 0) print line
- }
-' contract/release/publish-set.toml >"$order_file"
-
-if [[ ! -s $order_file ]]; then
- echo "publish_order.crates list is empty"
- exit 1
-fi
-
-selected_file="$(mktemp)"
-requested_file="$(mktemp)"
-trap 'rm -f "$order_file" "$selected_file" "$requested_file"' EXIT
-
-crate_version_visible() {
- local crate="$1"
- curl -fsSL "https://crates.io/api/v1/crates/${crate}/${release_version}" >/dev/null 2>&1
-}
-
-seconds_until_http_date() {
- local retry_after="$1"
- python3 - "$retry_after" <<'PY'
-import datetime
-import email.utils
-import sys
-
-retry_after = sys.argv[1].strip()
-try:
- target = email.utils.parsedate_to_datetime(retry_after)
-except Exception:
- print(0)
- raise SystemExit(0)
-
-if target.tzinfo is None:
- target = target.replace(tzinfo=datetime.timezone.utc)
-
-now = datetime.datetime.now(datetime.timezone.utc)
-remaining = (target - now).total_seconds()
-print(max(1, int(remaining) + 1))
-PY
-}
-
-publish_with_retry() {
- local crate="$1"
- local attempt=1
- while true; do
- local log_file
- log_file="$(mktemp)"
- if cargo publish --locked -p "$crate" >"$log_file" 2>&1; then
- cat "$log_file"
- rm -f "$log_file"
- return 0
- fi
-
- cat "$log_file"
-
- if grep -Fq "already uploaded" "$log_file"; then
- echo "crate ${crate} version ${release_version} is already uploaded"
- rm -f "$log_file"
- return 0
- fi
-
- if grep -Fq "429 Too Many Requests" "$log_file"; then
- local retry_after
- retry_after="$(sed -n 's/.*Please try again after \(.*GMT\).*/\1/p' "$log_file" | head -n1)"
- local sleep_secs=0
- if [[ -n $retry_after ]]; then
- sleep_secs="$(seconds_until_http_date "$retry_after")"
- fi
- if [[ $sleep_secs -le 0 ]]; then
- sleep_secs=$((30 + attempt * 15))
- fi
- echo "publish rate-limited for ${crate}; retry ${attempt} in ${sleep_secs}s"
- rm -f "$log_file"
- sleep "$sleep_secs"
- attempt=$((attempt + 1))
- continue
- fi
-
- rm -f "$log_file"
- return 1
- done
-}
-
-if [[ -n $requested_raw ]]; then
- for token in $requested_raw; do
- [[ -n $token ]] || continue
- echo "$token" >>"$requested_file"
- done
- sort -u "$requested_file" -o "$requested_file"
-
- while IFS= read -r token; do
- if ! grep -Fxq "$token" "$order_file"; then
- echo "requested crate is not in publish_order.crates: ${token}"
- exit 1
- fi
- done <"$requested_file"
-
- while IFS= read -r crate; do
- [[ -n $crate ]] || continue
- if grep -Fxq "$crate" "$requested_file"; then
- echo "$crate" >>"$selected_file"
- fi
- done <"$order_file"
-else
- cp "$order_file" "$selected_file"
-fi
-
-while IFS= read -r crate; do
- [ -n "$crate" ] || continue
- if [[ $mode == "dry-run" ]]; then
- log_file="$(mktemp)"
- if cargo publish --dry-run --locked --allow-dirty -p "$crate" >"$log_file" 2>&1; then
- cat "$log_file"
- rm -f "$log_file"
- continue
- fi
-
- missing_dep="$(sed -n 's/.*no matching package named `\([^`]*\)`.*/\1/p' "$log_file" | head -n1)"
- if [[ -n $missing_dep ]] && grep -Fxq "$missing_dep" "$order_file"; then
- echo "dry-run defer for ${crate}: dependency ${missing_dep} is not yet published"
- rm -f "$log_file"
- continue
- fi
-
- cat "$log_file"
- rm -f "$log_file"
- exit 1
- fi
-
- if crate_version_visible "$crate"; then
- echo "skip ${crate}: version ${release_version} already visible on crates.io"
- continue
- fi
-
- publish_with_retry "$crate"
- for attempt in $(seq 1 30); do
- if crate_version_visible "$crate"; then
- break
- fi
- if [[ $attempt == "30" ]]; then
- echo "crate ${crate} version ${release_version} not visible on crates.io after publish"
- exit 1
- fi
- sleep 10
- done
-done <"$selected_file"
-
-echo "publish sequence complete for release ${release_version}"