返回 CodeWhale
publish-crates.sh
根目录 / scripts / release / publish-crates.sh
1 #!/usr/bin/env bash
2 set -euo pipefail
3
4 script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5 # shellcheck source=scripts/release/crates.sh
6 source "${script_dir}/crates.sh"
7
8 mode="${1:-dry-run}"
9 case "${mode}" in
10 dry-run|publish) ;;
11 *)
12 echo "usage: $0 [dry-run|publish]" >&2
13 exit 1
14 ;;
15 esac
16
17 # Multi-package publication verification was stabilized in Cargo 1.90.
18 # Release tooling can require a newer Cargo than the runtime's Rust MSRV.
19 cargo_version="$(cargo --version)"
20 if [[ ! "${cargo_version}" =~ ^cargo[[:space:]]+([0-9]+)\.([0-9]+)\. ]] ||
21 (( BASH_REMATCH[1] < 1 || (BASH_REMATCH[1] == 1 && BASH_REMATCH[2] < 90) )); then
22 echo "Release preflight requires Cargo 1.90 or newer; found ${cargo_version}. Run rustup update stable and use that toolchain." >&2
23 exit 1
24 fi
25
26 packages=("${release_crates[@]}")
27 crates_user_agent="CodeWhale release publish check (https://github.com/Hmbown/CodeWhale)"
28
29 workspace_version=""
30
31 metadata_inventory="$(
32 python3 "${script_dir}/validate-crate-publish-order.py" "${packages[@]}"
33 )"
34 while IFS=$'\t' read -r kind name value; do
35 case "${kind}" in
36 version)
37 workspace_version="${name}"
38 ;;
39 esac
40 done <<<"${metadata_inventory}"
41
42 if [[ -z "${workspace_version}" ]]; then
43 echo "Could not determine workspace version." >&2
44 exit 1
45 fi
46
47 echo "Crate publication order OK: ${#packages[@]} workspace crates."
48
49 if [[ "${mode}" == "publish" ]]; then
50 "${script_dir}/require-release-tag-checkout.sh"
51 "${script_dir}/verify-release-assets.sh"
52 fi
53
54 # Verify the complete release together, including Cargo's publication checks.
55 # Unpublished dependencies resolve through a temporary local registry, and
56 # each unpacked tarball builds before the first real upload is attempted.
57 package_args=(--dry-run --locked --registry crates-io)
58 if [[ "${mode}" == "dry-run" ]]; then
59 package_args+=(--allow-dirty)
60 fi
61 for package in "${packages[@]}"; do
62 package_args+=(-p "${package}")
63 done
64
65 echo "Verifying all ${#packages[@]} release package tarballs before any upload..."
66 cargo publish "${package_args[@]}"
67 if [[ "${mode}" == "dry-run" ]]; then
68 echo "Release package verification OK; no crates uploaded."
69 exit 0
70 fi
71
72 crate_version_exists() {
73 local crate_name="$1"
74 local crate_version="$2"
75 curl -fsSL -A "${crates_user_agent}" "https://crates.io/api/v1/crates/${crate_name}/${crate_version}" >/dev/null 2>&1
76 }
77
78 wait_for_crate_version() {
79 local crate_name="$1"
80 local crate_version="$2"
81 local attempts=30
82
83 for ((attempt = 1; attempt <= attempts; attempt += 1)); do
84 if crate_version_exists "${crate_name}" "${crate_version}"; then
85 return 0
86 fi
87 echo "Waiting for ${crate_name} ${crate_version} to appear on crates.io (${attempt}/${attempts})..."
88 sleep 10
89 done
90
91 echo "Timed out waiting for ${crate_name} ${crate_version} to appear on crates.io" >&2
92 return 1
93 }
94
95 for package in "${packages[@]}"; do
96 echo "::group::${mode} ${package}"
97 if crate_version_exists "${package}" "${workspace_version}"; then
98 echo "Skipping ${package} ${workspace_version}; already published."
99 else
100 cargo publish --locked --registry crates-io -p "${package}"
101 wait_for_crate_version "${package}" "${workspace_version}"
102 fi
103 echo "::endgroup::"
104 done
105
105 lines BASH