From 291ed260165c3298f7cebf231c24c00fdc942df3 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:20:47 -0500 Subject: [PATCH 1/9] xtask: Move run_cmd to util module --- xtask/src/main.rs | 11 +++-------- xtask/src/util.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 xtask/src/util.rs diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 1ffd801..5891049 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -6,22 +6,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod util; + use std::env; use std::process::{exit, Command}; +use util::run_cmd; const FEAT_OPTIONS: [bool; 2] = [false, true]; const FEAT_BYTEMUCK: &str = "bytemuck"; const FEAT_SERDE: &str = "serde"; const FEAT_STD: &str = "std"; -fn run_cmd(mut cmd: Command) { - println!("Running: {}", format!("{cmd:?}").replace('"', "")); - let status = cmd.status().expect("failed to launch"); - if !status.success() { - panic!("command failed: {status}"); - } -} - #[derive(Clone, Copy)] enum CargoAction { Test, diff --git a/xtask/src/util.rs b/xtask/src/util.rs new file mode 100644 index 0000000..9553a7d --- /dev/null +++ b/xtask/src/util.rs @@ -0,0 +1,17 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::process::Command; + +pub fn run_cmd(mut cmd: Command) { + println!("Running: {}", format!("{cmd:?}").replace('"', "")); + let status = cmd.status().expect("failed to launch"); + if !status.success() { + panic!("command failed: {status}"); + } +} From 25c6f4d1bc560a8a64242141df73fe522d7a87bb Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:24:31 -0500 Subject: [PATCH 2/9] xtask: Return Result from run_cmd --- Cargo.lock | 9 +++++++++ xtask/Cargo.toml | 3 +++ xtask/src/main.rs | 4 ++-- xtask/src/util.rs | 9 ++++++--- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3408d0..4376e0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + [[package]] name = "basic-toml" version = "0.1.7" @@ -246,3 +252,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "xtask" version = "0.0.0" +dependencies = [ + "anyhow", +] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index a6a4c0d..9634fb7 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -12,3 +12,6 @@ version = "0.0.0" edition = "2021" publish = false license = "MIT OR Apache-2.0" + +[dependencies] +anyhow = "1.0.75" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 5891049..44a25a1 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -52,8 +52,8 @@ fn get_cargo_cmd( } fn test_package(package: &str, features: &[&str]) { - run_cmd(get_cargo_cmd(CargoAction::Lint, package, features)); - run_cmd(get_cargo_cmd(CargoAction::Test, package, features)); + run_cmd(get_cargo_cmd(CargoAction::Lint, package, features)).unwrap(); + run_cmd(get_cargo_cmd(CargoAction::Test, package, features)).unwrap(); } fn test_uguid() { diff --git a/xtask/src/util.rs b/xtask/src/util.rs index 9553a7d..c2ba171 100644 --- a/xtask/src/util.rs +++ b/xtask/src/util.rs @@ -6,12 +6,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use anyhow::{bail, Result}; use std::process::Command; -pub fn run_cmd(mut cmd: Command) { +pub fn run_cmd(mut cmd: Command) -> Result<()> { println!("Running: {}", format!("{cmd:?}").replace('"', "")); let status = cmd.status().expect("failed to launch"); - if !status.success() { - panic!("command failed: {status}"); + if status.success() { + Ok(()) + } else { + bail!("command failed: {status}"); } } From 79303e7bdaf66b1006229fed63a7b4041435c3c3 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:36:36 -0500 Subject: [PATCH 3/9] xtask: Add get_cmd_stdout --- xtask/src/util.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/xtask/src/util.rs b/xtask/src/util.rs index c2ba171..43a9473 100644 --- a/xtask/src/util.rs +++ b/xtask/src/util.rs @@ -9,8 +9,12 @@ use anyhow::{bail, Result}; use std::process::Command; -pub fn run_cmd(mut cmd: Command) -> Result<()> { +fn print_cmd(cmd: &Command) { println!("Running: {}", format!("{cmd:?}").replace('"', "")); +} + +pub fn run_cmd(mut cmd: Command) -> Result<()> { + print_cmd(&cmd); let status = cmd.status().expect("failed to launch"); if status.success() { Ok(()) @@ -18,3 +22,13 @@ pub fn run_cmd(mut cmd: Command) -> Result<()> { bail!("command failed: {status}"); } } + +pub fn get_cmd_stdout(mut cmd: Command) -> Result> { + print_cmd(&cmd); + let output = cmd.output().expect("failed to launch"); + if output.status.success() { + Ok(output.stdout) + } else { + bail!("command failed: {}", output.status); + } +} From 9aebf2bcb002ed15491d38d18e8b6b0db04232af Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:29:54 -0500 Subject: [PATCH 4/9] xtask: Add Package enum --- xtask/src/main.rs | 14 ++++++++------ xtask/src/package.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 xtask/src/package.rs diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 44a25a1..03ec87d 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -6,8 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod package; mod util; +use package::Package; use std::env; use std::process::{exit, Command}; use util::run_cmd; @@ -34,11 +36,11 @@ impl CargoAction { fn get_cargo_cmd( action: CargoAction, - package: &str, + package: Package, features: &[&str], ) -> Command { let mut cmd = Command::new("cargo"); - cmd.args([action.as_str(), "--package", package]); + cmd.args([action.as_str(), "--package", package.name()]); if !features.is_empty() { cmd.args(["--features", &features.join(",")]); } @@ -51,7 +53,7 @@ fn get_cargo_cmd( cmd } -fn test_package(package: &str, features: &[&str]) { +fn test_package(package: Package, features: &[&str]) { run_cmd(get_cargo_cmd(CargoAction::Lint, package, features)).unwrap(); run_cmd(get_cargo_cmd(CargoAction::Test, package, features)).unwrap(); } @@ -71,7 +73,7 @@ fn test_uguid() { features.push(FEAT_STD); } - test_package("uguid", &features); + test_package(Package::Uguid, &features); } } } @@ -88,7 +90,7 @@ fn test_gpt_disk_types() { features.push(FEAT_STD); } - test_package("gpt_disk_types", &features); + test_package(Package::GptDiskTypes, &features); } } } @@ -102,7 +104,7 @@ fn test_gpt_disk_io() { ]; for features in feature_lists { - test_package("gpt_disk_io", &features); + test_package(Package::GptDiskIo, &features); } } diff --git a/xtask/src/package.rs b/xtask/src/package.rs new file mode 100644 index 0000000..389066d --- /dev/null +++ b/xtask/src/package.rs @@ -0,0 +1,26 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// Public packages in the workspace. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Package { + Uguid, + GptDiskTypes, + GptDiskIo, +} + +impl Package { + /// Package name. + pub fn name(self) -> &'static str { + match self { + Self::Uguid => "uguid", + Self::GptDiskTypes => "gpt_disk_types", + Self::GptDiskIo => "gpt_disk_io", + } + } +} From 73f8cb7653809bfce69a097ed7b722b8f3f973b1 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:35:10 -0500 Subject: [PATCH 5/9] xtask: Add Package::publish_order --- xtask/src/package.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xtask/src/package.rs b/xtask/src/package.rs index 389066d..3a2812c 100644 --- a/xtask/src/package.rs +++ b/xtask/src/package.rs @@ -23,4 +23,10 @@ impl Package { Self::GptDiskIo => "gpt_disk_io", } } + + /// The order in which to publish packages. Later packages depend on + /// earlier ones. + pub fn publish_order() -> &'static [Self] { + &[Self::Uguid, Self::GptDiskTypes, Self::GptDiskIo] + } } From 3b6533eb8490f59b0adae541dd8ec840d935c28b Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:06:02 -0500 Subject: [PATCH 6/9] xtask: Stub in auto_release command --- xtask/src/main.rs | 6 ++++++ xtask/src/release.rs | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 xtask/src/release.rs diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 03ec87d..c561ed3 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -7,6 +7,7 @@ // except according to those terms. mod package; +mod release; mod util; use package::Package; @@ -110,11 +111,13 @@ fn test_gpt_disk_io() { fn main() { let args: Vec<_> = env::args().collect(); + let arg_auto_release = "auto_release"; let arg_test_all = "test_all"; let arg_test_uguid = "test_uguid"; let arg_test_gpt_disk_types = "test_gpt_disk_types"; let arg_test_gpt_disk_io = "test_gpt_disk_io"; let actions = &[ + arg_auto_release, arg_test_all, arg_test_uguid, arg_test_gpt_disk_types, @@ -126,6 +129,9 @@ fn main() { } let action = &args[1]; + if action == arg_auto_release { + release::auto_release(); + } if action == arg_test_all || action == arg_test_uguid { test_uguid(); } diff --git a/xtask/src/release.rs b/xtask/src/release.rs new file mode 100644 index 0000000..718d168 --- /dev/null +++ b/xtask/src/release.rs @@ -0,0 +1,11 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn auto_release() { + todo!() +} From 6ea378fef9629dc9fa7b636a8717ea124af7dfce Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:19:16 -0500 Subject: [PATCH 7/9] xtask: Implement auto_release command --- .deny.toml | 11 + Cargo.lock | 517 +++++++++++++++++++++++++++++++++++++++++++ xtask/Cargo.toml | 3 + xtask/src/main.rs | 2 +- xtask/src/release.rs | 212 +++++++++++++++++- 5 files changed, 742 insertions(+), 3 deletions(-) diff --git a/.deny.toml b/.deny.toml index f756d8a..8cb9d2b 100644 --- a/.deny.toml +++ b/.deny.toml @@ -12,4 +12,15 @@ allow = [ "MIT", "MPL-2.0", "Unicode-DFS-2016", + + # Needed for xtask only. + "ISC", + "OpenSSL", +] + +[[licenses.clarify]] +name = "ring" +expression = "MIT AND ISC AND OpenSSL" +license-files = [ + { path = "LICENSE", hash = 0xbd0eed23 } ] diff --git a/Cargo.lock b/Cargo.lock index 4376e0d..b234420 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,24 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "anyhow" version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + [[package]] name = "basic-toml" version = "0.1.7" @@ -43,6 +55,79 @@ dependencies = [ "syn", ] +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "crates-index" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f3e3ef6d547bbf1213b3dabbf0b01a500fbd0924abf818b563a4bc2c85296c" +dependencies = [ + "hex", + "home", + "http", + "memchr", + "rustc-hash", + "semver", + "serde", + "serde_derive", + "serde_json", + "smol_str", + "thiserror", + "toml", +] + [[package]] name = "crc" version = "3.0.1" @@ -58,6 +143,57 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "glob" version = "0.3.1" @@ -82,18 +218,106 @@ dependencies = [ "uguid", ] +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "http" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "libc" +version = "0.2.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + [[package]] name = "once_cell" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + [[package]] name = "proc-macro2" version = "1.0.70" @@ -112,12 +336,73 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.21.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +dependencies = [ + "serde", +] + [[package]] name = "serde" version = "1.0.193" @@ -149,6 +434,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "serde_test" version = "1.0.176" @@ -158,6 +452,21 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "syn" version = "2.0.39" @@ -178,6 +487,75 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "trybuild" version = "1.0.85" @@ -212,12 +590,73 @@ dependencies = [ "trybuild", ] +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ccd538d4a604753ebc2f17cd9946e89b77bf87f6a8e2309667c6f2e87855e3" +dependencies = [ + "base64", + "flate2", + "http", + "log", + "once_cell", + "rustls", + "rustls-webpki", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + [[package]] name = "winapi" version = "0.3.9" @@ -249,9 +688,87 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + [[package]] name = "xtask" version = "0.0.0" dependencies = [ "anyhow", + "cargo_metadata", + "crates-index", + "ureq", ] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 9634fb7..2676b2c 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -15,3 +15,6 @@ license = "MIT OR Apache-2.0" [dependencies] anyhow = "1.0.75" +cargo_metadata = "0.18.1" +crates-index = "2.3.0" +ureq = { version = "2.8.0", features = ["http-interop"] } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index c561ed3..526b554 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -130,7 +130,7 @@ fn main() { let action = &args[1]; if action == arg_auto_release { - release::auto_release(); + release::auto_release().unwrap(); } if action == arg_test_all || action == arg_test_uguid { test_uguid(); diff --git a/xtask/src/release.rs b/xtask/src/release.rs index 718d168..7a3b44c 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs @@ -6,6 +6,214 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub fn auto_release() { - todo!() +use crate::package::Package; +use crate::util; +use anyhow::{Context, Result}; +use cargo_metadata::{Metadata, MetadataCommand}; +use crates_index::SparseIndex; +use std::env; +use std::process::Command; + +/// Entry point for the auto-release process. This is intended to be run from a +/// Github Actions workflow, see `.github/workflows/release.yml`. +pub fn auto_release() -> Result<()> { + let commit_sha = get_commit_sha()?; + let commit_message_subject = get_commit_message_subject(&commit_sha)?; + + if !commit_message_subject.starts_with("release:") { + println!("{commit_sha} does not contain the release trigger"); + return Ok(()); + } + + fetch_git_tags()?; + + let local_metadata = get_local_package_metadata()?; + let mut index = SparseIndex::new_cargo_default()?; + + for package in Package::publish_order() { + auto_release_package( + *package, + &local_metadata, + &mut index, + &commit_sha, + )?; + } + + Ok(()) +} + +/// Release a single package, if needed. +/// +/// This publishes to crates.io if the corresponding version does not already +/// exist there, and also pushes a new git tag if one doesn't exist yet. +fn auto_release_package( + package: Package, + local_metadata: &Metadata, + index: &mut SparseIndex, + commit_sha: &str, +) -> Result<()> { + let local_version = get_local_package_version(package, local_metadata)?; + println!("local version of {} is {local_version}", package.name()); + + // Create the remote git tag if it doesn't exist. + let tag = get_git_tag_name(package, &local_version); + if does_git_tag_exist(&tag)? { + println!("git tag {tag} already exists"); + } else { + make_and_push_git_tag(&tag, commit_sha)?; + } + + // Create the crates.io release if it doesn't exist. + if does_crates_io_release_exist(package, &local_version, index)? { + println!( + "{}-{local_version} has already been published", + package.name() + ); + } else { + publish_package(package)?; + } + + Ok(()) +} + +/// Get the commit to operate on from the `GITHUB_SHA` env var. When running in +/// Github Actions, this will be set to the SHA of the merge commit that was +/// pushed to the branch. +fn get_commit_sha() -> Result { + let commit_var_name = "GITHUB_SHA"; + env::var(commit_var_name) + .context(format!("failed to get env var {commit_var_name}")) +} + +/// Create a git command with the given args. +fn get_git_command(args: [&str; N]) -> Command { + let mut cmd = Command::new("git"); + cmd.args(args); + cmd +} + +/// Get the subject of the commit message for the given commit. +fn get_commit_message_subject(commit_sha: &str) -> Result { + let cmd = get_git_command([ + "log", + "-1", + // Only get the subject of the commit message. + "--format=format:%s", + commit_sha, + ]); + let output = util::get_cmd_stdout(cmd)?; + String::from_utf8(output).context("commit message is not utf-8") +} + +/// Use the `cargo_metadata` crate to get local info about packages in the +/// workspace. +fn get_local_package_metadata() -> Result { + let mut cmd = MetadataCommand::new(); + // Ignore deps, we only need local packages. + cmd.no_deps(); + Ok(cmd.exec()?) +} + +/// Fetch git tags from the remote. +fn fetch_git_tags() -> Result<()> { + let cmd = get_git_command(["fetch", "--tags"]); + util::run_cmd(cmd) +} + +/// Format a package version as a git tag. +fn get_git_tag_name(package: Package, local_version: &str) -> String { + format!("{}-v{}", package.name(), local_version) +} + +/// Check if a git tag exists locally. +/// +/// All git tags were fetched at the start of auto-release, so checking locally +/// is sufficient. +fn does_git_tag_exist(tag: &str) -> Result { + let cmd = get_git_command(["tag", "--list", tag]); + let output = util::get_cmd_stdout(cmd)?; + let output = String::from_utf8(output).context("git tag is not utf-8")?; + + Ok(output.lines().any(|line| line == tag)) +} + +/// Create a git tag locally and push it. +fn make_and_push_git_tag(tag: &str, commit_sha: &str) -> Result<()> { + // Create the tag. + let cmd = get_git_command(["tag", tag, commit_sha]); + util::run_cmd(cmd)?; + + // Push it. + let cmd = get_git_command(["push", "--tags"]); + util::run_cmd(cmd) +} + +/// Update the local crates.io cache. +/// +/// Based on +fn update_index(index: &mut SparseIndex, package: Package) -> Result<()> { + let crate_name = package.name(); + + println!("fetching updates for {}", package.name()); + let request: ureq::Request = + index.make_cache_request(crate_name).unwrap().into(); + let response = request.call()?; + + index.parse_cache_response(crate_name, response.into(), true)?; + + Ok(()) +} + +/// Check if a new release of `package` should be published. +fn does_crates_io_release_exist( + package: Package, + local_version: &str, + index: &mut SparseIndex, +) -> Result { + let remote_versions = get_remote_package_versions(package, index)?; + if remote_versions.contains(&local_version.to_string()) { + return Ok(true); + } + + Ok(false) +} + +/// Get the local version of `package`. +fn get_local_package_version( + package: Package, + local_metadata: &Metadata, +) -> Result { + let metadata = local_metadata + .packages + .iter() + .find(|pm| pm.name == package.name()) + .context(format!( + "failed to find {} in local metadata", + package.name() + ))?; + Ok(metadata.version.to_string()) +} + +/// Get all remote versions of `package`. +fn get_remote_package_versions( + package: Package, + index: &mut SparseIndex, +) -> Result> { + // The local cache may be out of date, fetch updates from the remote. + update_index(index, package)?; + + let cr = index.crate_from_cache(package.name())?; + + Ok(cr + .versions() + .iter() + .map(|v| v.version().to_string()) + .collect()) +} + +/// Publish `package` to crates.io. +fn publish_package(package: Package) -> Result<()> { + let mut cmd = Command::new("cargo"); + cmd.args(["publish", "--package", package.name()]); + util::run_cmd(cmd) } From 9871e0365388c79c29167bf2a7a543366228bbd2 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 22:58:46 -0500 Subject: [PATCH 8/9] github: Add release action --- .github/workflows/release.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..4f0e340 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +name: Release +on: + push: + branches: + - main +permissions: + contents: write +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - run: cargo xtask auto_release + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} From bf355880d3f0d4585c861986f919e68051298ff2 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Sat, 11 Nov 2023 23:23:02 -0500 Subject: [PATCH 9/9] docs: Add release_process.md --- docs/release_process.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/release_process.md diff --git a/docs/release_process.md b/docs/release_process.md new file mode 100644 index 0000000..92d92cc --- /dev/null +++ b/docs/release_process.md @@ -0,0 +1,40 @@ +# Release process + +To release new versions of one or more packages in the workspace: + +1. Create a local branch and make these changes: + 1. Update the version of each package you want to release in the + corresponding `Cargo.toml`. Follow semver. + 2. If needed, update the dependency version in packages that depend + on the updated package. For example, if you are releasing changes + to `uguid` that require a major version bump, the dependency on + `uguid` in `gpt_disk_types` should be updated. Ditto for a minor + version bump if the dependent package requires any of the new + functionality. Patch version bumps do not require a change in the + dependent package. Note that in cargo's version of semver, `0.x.y` + treats `x` as the major version number. + 3. Update the changelogs. +2. Commit those changes. The commit message subject must start with + `release:`. Without that prefix, the automatic part of the release + process will not run. +3. Push the branch and create a PR. +4. When the PR is reviewed and merged, the automatic release process + will kick off. + +## The automatic part + +The rest of the release process is triggered by +`.github/workflows/release.yml`, which runs when commits are pushed to +the main branch. It runs `cargo xtask auto_publish`. + +The `auto_publish` command gets the local version of each package and, +if necessary, creates a remote git tag and publishes to crates.io. If +the git tag already exists, that part is skipped. If the crates.io +release already exists, that part is skipped. + +## Crates.io token + +Releasing to crates.io requires an API token. That is passed to the job +via a repository secret called `CARGO_REGISTRY_TOKEN`. The secret is +configured in the repo settings. When creating an API token, restrict +the scope to `publish-update`.