From fccefd13b5611c88da96abe7dbf62d708dfd66ac Mon Sep 17 00:00:00 2001 From: Brian Hardock Date: Tue, 16 Jun 2026 12:12:23 -0600 Subject: [PATCH] Fix ci/publish script Signed-off-by: Brian Hardock --- ci/publish.rs | 123 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 49 deletions(-) diff --git a/ci/publish.rs b/ci/publish.rs index 1fcbbac..74630d5 100644 --- a/ci/publish.rs +++ b/ci/publish.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{Command, Output, Stdio}; use std::thread; use std::time::Duration; @@ -285,19 +285,17 @@ fn publish(krate: &Crate) -> bool { // First make sure the crate isn't already published at this version. This // script may be re-run and there's no need to re-attempt previous work. - let output = Command::new("curl") - .arg(&format!("https://crates.io/api/v1/crates/{}", krate.name)) - .output() - .expect("failed to invoke `curl`"); - if output.status.success() - && String::from_utf8_lossy(&output.stdout) - .contains(&format!("\"newest_version\":\"{}\"", krate.version)) - { - println!( - "skip publish {} because {} is latest version", - krate.name, krate.version, - ); - return true; + match curl(&format!("https://crates.io/api/v1/crates/{}", krate.name)) { + Some(output) => { + if output.contains(&format!("\"newest_version\":\"{}\"", krate.version)) { + println!( + "skip publish {} because {} is latest version", + krate.name, krate.version, + ); + return true; + } + } + None => return false, } let status = Command::new("cargo") @@ -311,44 +309,30 @@ fn publish(krate: &Crate) -> bool { return false; } - // After we've published then make sure that the `wasmtime-publish` group is - // added to this crate for future publications. If it's already present - // though we can skip the `cargo owner` modification. - let output = Command::new("curl") - .arg(&format!( - "https://crates.io/api/v1/crates/{}/owners", - krate.name - )) - .output() - .expect("failed to invoke `curl`"); - if output.status.success() - && String::from_utf8_lossy(&output.stdout).contains("wasmtime-publish") - { - println!( - "wasmtime-publish already listed as an owner of {}", - krate.name - ); - return true; - } + true +} - // Note that the status is ignored here. This fails most of the time because - // the owner is already set and present, so we only want to add this to - // crates which haven't previously been published. - let status = Command::new("cargo") - .arg("owner") - .arg("-a") - .arg("github:bytecodealliance:wasmtime-publish") - .arg(&krate.name) - .status() - .expect("failed to run cargo"); - if !status.success() { - panic!( - "FAIL: failed to add wasmtime-publish as owner `{}`: {}", - krate.name, status - ); +fn curl(url: &str) -> Option { + let output = cmd_output( + Command::new("curl") + .arg("--user-agent") + .arg("bytecodealliance/wac auto-publish script") + .arg(url), + ); + if !output.status.success() { + println!("failed to curl: {}", output.status); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + return None; } + Some(String::from_utf8_lossy(&output.stdout).into()) +} - true +fn cmd_output(cmd: &mut Command) -> Output { + eprintln!("Running: `{:?}`", cmd); + match cmd.output() { + Ok(o) => o, + Err(e) => panic!("Failed to run `{:?}`: {}", cmd, e), + } } // Verify the current tree is publish-able to crates.io. The intention here is @@ -373,6 +357,7 @@ fn verify(crates: &[Crate]) { if !krate.publish { continue; } + verify_crates_io(krate); verify_and_vendor(&krate); } @@ -404,4 +389,44 @@ fn verify(crates: &[Crate]) { ) .unwrap(); } + + fn verify_crates_io(krate: &Crate) { + let name = &krate.name; + let Some(owners) = curl(&format!("https://crates.io/api/v1/crates/{name}/owners")) else { + panic!( + " +failed to get owners for {name} + +If this crate does not exist on crates.io yet please ping wac maintainers to +add the crate on crates.io as a small shim. When doing so please remind them +that the trusted publishing workflow must be configured as well. +", + name = name, + ); + }; + + // This is the id of the `wasmtime-publish` user on crates.io + if !owners.contains("\"id\":73222,") { + panic!( + " +crate {name} is not owned by wasmtime-publish, please run: + + cargo owner -a wasmtime-publish {name} +", + name = name, + ); + } + + if owners.split("\"id\"").count() != 2 { + panic!( + " +crate {name} is not exclusively owned by wasmtime-publish + +Please contact wac maintainers to ensure that `wasmtime-publish` is the +only listed owner of the crate. +", + name = name, + ); + } + } }