ci(publish-crates): set User-Agent + treat "already exists" as success (#117)

Two related fixes uncovered while recovering the v0.5.0 publish.

1. crates.io API requires a User-Agent header. The `publish_if_new`
   skip check was doing a bare `curl -fsSL https://crates.io/api/...`
   which crates.io rejects with HTTP 403. With `-f` curl exits
   non-zero, the pipeline returns empty, the script doesn't recognize
   already-published crates, and we fall through to a real publish
   attempt. On a re-run that means cargo publish errors with
   "already exists on crates.io index" for crates that DID publish
   successfully on the previous run.

   Fix: send a `User-Agent: ModernRelay-omnigraph-ci (URL)` header.

2. Defense in depth: even with the UA, the API could hiccup. If the
   skip check misses an existing version and cargo publish errors
   with "already exists on crates.io index", treat as success
   instead of failing the whole run. This makes the workflow
   re-runnable after any partial publish without needing manual
   intervention.

Both fixes are required to recover from the v0.5.0 partial publish
where omnigraph-compiler@0.5.0 made it through but the run failed
before omnigraph-policy / engine / server / cli — re-triggering the
workflow now succeeds end-to-end.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew Altshuler 2026-05-23 14:19:17 +01:00 committed by GitHub
parent 1a9f8b1f7f
commit 587fbeabd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -80,8 +80,15 @@ jobs:
version=$(cargo metadata --format-version=1 --no-deps \
| jq -r --arg c "$crate" '.packages[] | select(.name==$c) | .version')
# crates.io API requires a User-Agent header — without it the
# API responds 403 and the skip check below would silently
# fall through to a real publish attempt that errors with
# "already exists on crates.io index" when re-running after a
# partial publish. Send a UA naming the workflow.
local current
current=$(curl -fsSL "https://crates.io/api/v1/crates/${crate}" \
current=$(curl -fsSL \
-A 'ModernRelay-omnigraph-ci (https://github.com/ModernRelay/omnigraph)' \
"https://crates.io/api/v1/crates/${crate}" \
| jq -r '.crate.max_version' || echo "")
if [[ "$current" == "$version" ]]; then
@ -90,7 +97,20 @@ jobs:
fi
echo "==> publishing ${crate} ${version} (current crates.io: ${current:-none})"
cargo publish -p "$crate" --locked
# Defense in depth: if the skip check missed an existing
# version (e.g. crates.io API hiccup), cargo publish errors
# with "already exists on crates.io index". Treat that as
# success so the workflow can be re-run idempotently.
local output
if ! output=$(cargo publish -p "$crate" --locked 2>&1); then
echo "$output"
if echo "$output" | grep -q "already exists on crates.io"; then
echo "==> ${crate} ${version} was already published; treating as success"
return 0
fi
return 1
fi
echo "$output"
}
# Order matters: each crate must precede anything that depends on it.