Auto merge of #4551 - natboehm:owner-invite-messages, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 30 Sep 2017 07:37:59 +0000 (07:37 +0000)
committerCarol (Nichols || Goulding) <carol.nichols@gmail.com>
Tue, 3 Oct 2017 14:35:02 +0000 (10:35 -0400)
Owner invite messages

This PR addresses issue #4537, the plan for `cargo owner --add` requiring invitations in Cargo and the encompassing issue [#924](https://github.com/rust-lang/crates.io/issues/924), requiring an invite to add someone as an owner in Crates.io.

Regarding the Cargo issue, we went with Option 2, changing the `add_owners` function to decode a struct sent from Crates containing a `boolean` and `String`, the `boolean` being the response status and `String` being the success message. This may sound redundant however we concluded that using both of these fields were necessary to support older versions of Cargo - if we changed Crates.io to only return the `String` message on success this would likely break systems using the older version of `add_owner` expecting a response containing a `boolean`. Matching this schema, `add_owners` on the Crates.io side will soon return a struct containing a `boolean` and `String`, and instead of adding a new crate owner to the database will add a crate owner invite. If successful, `modify_owners` now prints the message sent from Crates.io instead of the old hardcoded message.

Resolves #4537

src/cargo/ops/registry.rs
src/crates-io/lib.rs

index f7153c19067f7abfc8ca27bdd5442bedfb91c0e1..6140a8bc224e48e4abc8908907e922e0c3ed1b77 100644 (file)
@@ -318,11 +318,11 @@ pub fn modify_owners(config: &Config, opts: &OwnersOptions) -> CargoResult<()> {
 
     if let Some(ref v) = opts.to_add {
         let v = v.iter().map(|s| &s[..]).collect::<Vec<_>>();
-        config.shell().status("Owner", format!("adding {:?} to crate {}",
-                                                    v, name))?;
-        registry.add_owners(&name, &v).map_err(|e| {
-            CargoError::from(format!("failed to add owners to crate {}: {}", name, e))
+        let msg = registry.add_owners(&name, &v).map_err(|e| {
+            CargoError::from(format!("failed to invite owners to crate {}: {}", name, e))
         })?;
+
+        config.shell().status("Owner", msg)?;
     }
 
     if let Some(ref v) = opts.to_remove {
index cd8df416d8d87ea6bd394b3f65eac017d62cb062..6caa46cf716fea830130b18a1f2023eec8f4ec38 100644 (file)
@@ -116,6 +116,7 @@ pub struct Warnings {
 }
 
 #[derive(Deserialize)] struct R { ok: bool }
+#[derive(Deserialize)] struct OwnerResponse { ok: bool, msg: String }
 #[derive(Deserialize)] struct ApiErrorList { errors: Vec<ApiError> }
 #[derive(Deserialize)] struct ApiError { detail: String }
 #[derive(Serialize)] struct OwnersReq<'a> { users: &'a [&'a str] }
@@ -137,19 +138,19 @@ impl Registry {
         }
     }
 
-    pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> {
+    pub fn add_owners(&mut self, krate: &str, owners: &[&str]) -> Result<String> {
         let body = serde_json::to_string(&OwnersReq { users: owners })?;
         let body = self.put(format!("/crates/{}/owners", krate),
                                  body.as_bytes())?;
-        assert!(serde_json::from_str::<R>(&body)?.ok);
-        Ok(())
+        assert!(serde_json::from_str::<OwnerResponse>(&body)?.ok);
+        Ok(serde_json::from_str::<OwnerResponse>(&body)?.msg)
     }
 
     pub fn remove_owners(&mut self, krate: &str, owners: &[&str]) -> Result<()> {
         let body = serde_json::to_string(&OwnersReq { users: owners })?;
         let body = self.delete(format!("/crates/{}/owners", krate),
                                     Some(body.as_bytes()))?;
-        assert!(serde_json::from_str::<R>(&body)?.ok);
+        assert!(serde_json::from_str::<OwnerResponse>(&body)?.ok);
         Ok(())
     }