diff --git a/tools/publisher/src/main.rs b/tools/publisher/src/main.rs index e3a81864580e27506f8697b129d714cca1b36b90..08896fc215a6afab5a55a58549fd7db8420fec37 100644 --- a/tools/publisher/src/main.rs +++ b/tools/publisher/src/main.rs @@ -26,7 +26,15 @@ mod subcommand; pub const SDK_REPO_CRATE_PATH: &str = "sdk"; pub const SDK_REPO_NAME: &str = "aws-sdk-rust"; pub const SMITHYRS_REPO_NAME: &str = "smithy-rs"; -pub const CRATE_OWNER: &str = "github:awslabs:rust-sdk-owners"; + +// Crate ownership for SDK crates. Crates.io requires that at least one owner +// is an individual rather than a team, so we use the automation user for that. +pub const CRATE_OWNERS: &[&str] = &[ + // https://github.com/orgs/awslabs/teams/rust-sdk-owners + "github:awslabs:rust-sdk-owners", + // https://github.com/aws-sdk-rust-ci + "aws-sdk-rust-ci", +]; #[derive(Parser, Debug)] #[clap(author, version, about)] diff --git a/tools/publisher/src/subcommand/publish.rs b/tools/publisher/src/subcommand/publish.rs index 9bec8b44fa32a02fe9d8f01ad1e6bd9de7bdc19e..ff30bb265d3ddbbcb7888dd53928de286ed77659 100644 --- a/tools/publisher/src/subcommand/publish.rs +++ b/tools/publisher/src/subcommand/publish.rs @@ -9,7 +9,7 @@ use crate::package::{ }; use crate::repo::{resolve_publish_location, Repository}; use crate::retry::{run_with_retry, BoxError, ErrorClass}; -use crate::CRATE_OWNER; +use crate::CRATE_OWNERS; use crate::{cargo, SDK_REPO_NAME}; use anyhow::{bail, Context, Result}; use clap::Parser; @@ -195,22 +195,36 @@ async fn correct_owner(package: &Package) -> Result<()> { Duration::from_secs(5), || async { let owners = cargo::GetOwners::new(&package.handle.name).spawn().await?; - let incorrect_owners = owners.iter().filter(|&owner| owner != CRATE_OWNER); - for incorrect_owner in incorrect_owners { - cargo::RemoveOwner::new(&package.handle.name, incorrect_owner) - .spawn() - .await - .context("remove incorrect owner")?; - info!( - "Removed incorrect owner `{}` from crate `{}`", - incorrect_owner, package.handle - ); + let mut added_individual = false; + for &crate_owner in CRATE_OWNERS { + if !owners.iter().any(|owner| owner == crate_owner) { + cargo::AddOwner::new(&package.handle.name, crate_owner) + .spawn() + .await?; + info!("Added `{}` as owner of `{}`", crate_owner, package.handle); + // Teams in crates.io start with `github:` while individuals are just the GitHub user name + added_individual |= !crate_owner.starts_with("github:"); + } } - if !owners.iter().any(|owner| owner == CRATE_OWNER) { - cargo::AddOwner::new(&package.handle.name, CRATE_OWNER) - .spawn() - .await?; - info!("Corrected crate ownership of `{}`", package.handle); + let incorrect_owners = owners + .iter() + .filter(|&owner| !CRATE_OWNERS.iter().any(|o| o == owner)); + for incorrect_owner in incorrect_owners { + // Adding an individual owner requires accepting an invite, so don't attempt to remove + // anyone if an owner was added, as removing the last individual owner may break. + // The next publish run will remove the incorrect owner. + if !added_individual { + cargo::RemoveOwner::new(&package.handle.name, incorrect_owner) + .spawn() + .await + .context("remove incorrect owner")?; + info!( + "Removed incorrect owner `{}` from crate `{}`", + incorrect_owner, package.handle + ); + } else { + info!("Skipping removal of incorrect owner `{}` from crate `{}` due to new owners", incorrect_owner, package.handle); + } } Result::<_, BoxError>::Ok(()) },