diff --git a/Cargo.lock b/Cargo.lock index 60f6edf..3091b83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,6 +201,38 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cc" version = "1.0.79" @@ -525,9 +557,11 @@ name = "cuddle-please-release-strategy" version = "0.1.0" dependencies = [ "anyhow", + "cargo_metadata", "pretty_assertions", "semver", "serde", + "serde_json", "tempdir", "tracing", "tracing-test", @@ -2197,6 +2231,9 @@ name = "semver" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +dependencies = [ + "serde", +] [[package]] name = "serde" diff --git a/Cargo.toml b/Cargo.toml index 16bc1a1..98896af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ clap = { version = "4.3.19", features = ["derive", "env"] } dotenv = { version = "0.15.0" } url = { version = "2.4.0" } serde_yaml = { version = "0.9.25" } +serde_json = { version = "*" } serde = { version = "1", features = ["derive"] } semver = "1.0.18" conventional_commit_parser = "0.9.4" diff --git a/ci/src/main.rs b/ci/src/main.rs index 6d5f8d5..c557b39 100644 --- a/ci/src/main.rs +++ b/ci/src/main.rs @@ -9,7 +9,6 @@ use clap::ValueEnum; use dagger_sdk::Platform; use dagger_sdk::QueryContainerOpts; -use futures::StreamExt; use crate::please_release::run_release_please; diff --git a/crates/cuddle-please-release-strategy/Cargo.toml b/crates/cuddle-please-release-strategy/Cargo.toml index 8869eac..1430c07 100644 --- a/crates/cuddle-please-release-strategy/Cargo.toml +++ b/crates/cuddle-please-release-strategy/Cargo.toml @@ -13,11 +13,13 @@ anyhow.workspace = true tracing.workspace = true serde.workspace = true semver.workspace = true +cargo_metadata = "0.17.0" [dev-dependencies] tracing-test = { workspace = true, features = ["no-env-filter"] } pretty_assertions.workspace = true tempdir.workspace = true +serde_json.workspace = true [features] rust-workspace = [] @@ -27,5 +29,6 @@ json-edit = [] yaml-edit = [] default = [ - "json-edit" + "json-edit", + "rust-workspace" ] diff --git a/crates/cuddle-please-release-strategy/src/lib.rs b/crates/cuddle-please-release-strategy/src/lib.rs index 8ff1005..7e8076f 100644 --- a/crates/cuddle-please-release-strategy/src/lib.rs +++ b/crates/cuddle-please-release-strategy/src/lib.rs @@ -1,6 +1,11 @@ #[cfg(feature = "json-edit")] mod json_edit; +#[cfg(feature = "rust-workspace")] +mod rust_workspace; mod strategy; #[cfg(feature = "json-edit")] pub use json_edit::JsonEditOptions; + +#[cfg(feature = "rust-workspace")] +pub use rust_workspace::RustWorkspaceOptions; diff --git a/crates/cuddle-please-release-strategy/src/rust_workspace.rs b/crates/cuddle-please-release-strategy/src/rust_workspace.rs new file mode 100644 index 0000000..0514011 --- /dev/null +++ b/crates/cuddle-please-release-strategy/src/rust_workspace.rs @@ -0,0 +1,72 @@ +use std::path::{Path, PathBuf}; + +use anyhow::Context; +use cargo_metadata::camino::{Utf8Path, Utf8PathBuf}; +use serde::{Deserialize, Serialize}; + +fn lock_step_default() -> bool { + true +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RustWorkspaceOptions { + #[serde(default = "lock_step_default")] + pub lock_step: bool, +} + +impl RustWorkspaceOptions { + pub fn execute(&self, path: &Path, next_version: impl AsRef) -> anyhow::Result<()> { + let members = self.get_workspace(path)?; + + Ok(()) + } + + pub fn get_workspace(&self, path: &Path) -> anyhow::Result> { + let entries = std::fs::read_dir(path) + .context(anyhow::anyhow!("could not read dir: {}", path.display()))? + .flatten() + .filter(|p| p.file_name().to_str().unwrap() == "Cargo.toml") + .collect::>(); + + let cargo_manifest_file = match entries.first() { + Some(x) => x, + None => anyhow::bail!("did not find any Cargo.toml in: {}", path.display()), + }; + + let mut cmd = cargo_metadata::MetadataCommand::new(); + + let manifest = cmd + .no_deps() + .manifest_path(cargo_manifest_file.path()) + .exec() + .context("could not parse manifest")?; + + let members = manifest.workspace_members.iter().collect::>(); + let workspace_members = manifest + .packages + .into_iter() + .filter(|p| members.contains(&&p.id)) + .map(|mut p| { + p.manifest_path = abs_path(&p.manifest_path); + + for dependency in p.dependencies.iter_mut() { + dependency.path = dependency.path.take().map(|path| abs_path(&path)) + } + + p + }) + .collect::>(); + + Ok(workspace_members) + } +} + +fn abs_path(path: &Utf8Path) -> Utf8PathBuf { + match path.canonicalize_utf8() { + Ok(path) => path, + Err(e) => { + tracing::debug!("failed to transform manifest_path into abs path: {}", path); + path.to_path_buf() + } + } +} diff --git a/crates/cuddle-please-release-strategy/tests/rust_workspace_test.rs b/crates/cuddle-please-release-strategy/tests/rust_workspace_test.rs new file mode 100644 index 0000000..f0594d4 --- /dev/null +++ b/crates/cuddle-please-release-strategy/tests/rust_workspace_test.rs @@ -0,0 +1,60 @@ +use cargo_metadata::{ + camino::{Utf8Path, Utf8PathBuf}, + Package, +}; +use cuddle_please_release_strategy::RustWorkspaceOptions; +use serde_json::json; +use tracing_test::traced_test; + +#[test] +#[traced_test] +fn test_can_read_manifest() { + let temp = tempdir::TempDir::new("test_rust_workspace_can_read_manifest").unwrap(); + let temp_path = temp.path(); + + std::fs::write( + temp_path.join("Cargo.toml"), + r#" +[workspace] +members = [ + "nested" +] + +[workspace.dependencies] +nested = { path = "nested" } + "#, + ) + .unwrap(); + + std::fs::create_dir_all(temp_path.join("nested")).unwrap(); + std::fs::write( + temp_path.join("nested").join("Cargo.toml"), + r#" +[package] +name = "nested" +version = "0.1.0" +edition = "2021" + +[dependencies] +nested.workspace = true + "#, + ) + .unwrap(); + std::fs::create_dir_all(temp_path.join("nested").join("src")).unwrap(); + std::fs::write( + temp_path.join("nested").join("src").join("lib.rs"), + r#" +#[test] +test () {} +"#, + ) + .unwrap(); + + let options = RustWorkspaceOptions { lock_step: true }; + + let members = options.get_workspace(temp_path).unwrap(); + + assert!(!members.is_empty()); + let first = members.first().unwrap(); + pretty_assertions::assert_eq!("nested", &first.name); +}