changepacks_core/
workspace.rs1use std::{collections::HashSet, path::Path};
2
3use crate::{Language, Package, update_type::UpdateType};
4use anyhow::Result;
5use async_trait::async_trait;
6
7#[async_trait]
12pub trait Workspace: std::fmt::Debug + Send + Sync {
13 fn name(&self) -> Option<&str>;
14 fn path(&self) -> &Path;
15 fn relative_path(&self) -> &Path;
16 fn version(&self) -> Option<&str>;
17 async fn update_version(&mut self, update_type: UpdateType) -> Result<()>;
20 fn language(&self) -> Language;
21
22 fn dependencies(&self) -> &HashSet<String>;
23 fn add_dependency(&mut self, dependency: &str);
24
25 fn is_changed(&self) -> bool;
26 fn set_changed(&mut self, changed: bool);
27
28 fn set_name(&mut self, name: String);
31
32 fn default_publish_command(&self) -> String;
34
35 fn default_dry_run_publish_command(&self) -> Option<String>;
41
42 crate::impl_shared_project_defaults!();
43
44 crate::impl_publish_flows!(crate::publish::WORKSPACE_DIR_NOT_FOUND);
45
46 crate::impl_publish_command_resolvers!();
47
48 fn update_workspace_dependencies<'life0, 'life1, 'life2, 'async_trait>(
63 &'life0 self,
64 _packages: &'life1 [&'life2 dyn Package],
65 ) -> ::core::pin::Pin<
66 ::std::boxed::Box<
67 dyn ::core::future::Future<Output = Result<()>> + ::core::marker::Send + 'async_trait,
68 >,
69 >
70 where
71 'life0: 'async_trait,
72 'life1: 'async_trait,
73 'life2: 'async_trait,
74 Self: ::core::marker::Sync + 'async_trait,
75 {
76 ::std::boxed::Box::pin(async move { Ok(()) })
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use crate::Config;
84 use crate::test_support::MockWorkspace;
85 use std::collections::BTreeMap;
86
87 crate::test_support::shared_project_default_tests!(
92 mock: MockWorkspace,
93 trait_name: Workspace,
94 kind: "workspace",
95 dir_not_found: "Workspace directory not found",
96 publishable_test: test_workspace_is_publishable_by_default,
97 );
98
99 #[test]
100 fn test_get_dry_run_publish_command_falls_back_to_workspace_default() {
101 let workspace =
102 MockWorkspace::with_paths(Some("test"), "/project/package.json", "package.json")
103 .with_language(Language::Node);
104 let config = Config::default();
105
106 assert_eq!(
109 workspace.get_dry_run_publish_command(&config).as_deref(),
110 Some("echo publish --dry-run")
111 );
112 }
113
114 #[test]
115 fn test_get_dry_run_publish_command_override_by_path() {
116 let workspace = MockWorkspace::with_paths(
117 Some("test"),
118 "/project/package.json",
119 "packages/core/package.json",
120 );
121 let mut publish_dry_run = BTreeMap::new();
122 publish_dry_run.insert(
123 "packages/core/package.json".to_string(),
124 "custom dry".to_string(),
125 );
126 let config = Config {
127 publish_dry_run,
128 ..Default::default()
129 };
130
131 assert_eq!(
133 workspace.get_dry_run_publish_command(&config).as_deref(),
134 Some("custom dry")
135 );
136 }
137
138 #[test]
139 fn test_get_dry_run_publish_command_override_by_language() {
140 let workspace =
141 MockWorkspace::with_paths(Some("test"), "/project/package.json", "package.json")
142 .with_language(Language::Node);
143 let mut publish_dry_run = BTreeMap::new();
144 publish_dry_run.insert(
145 "node".to_string(),
146 "npm publish --dry-run --tag next".to_string(),
147 );
148 let config = Config {
149 publish_dry_run,
150 ..Default::default()
151 };
152
153 assert_eq!(
155 workspace.get_dry_run_publish_command(&config).as_deref(),
156 Some("npm publish --dry-run --tag next")
157 );
158 }
159
160 #[tokio::test]
161 async fn test_update_workspace_dependencies_default() {
162 let workspace =
163 MockWorkspace::with_paths(Some("test"), "/project/package.json", "package.json");
164 let packages: Vec<&dyn Package> = vec![];
165
166 let result = workspace.update_workspace_dependencies(&packages).await;
167 assert!(result.is_ok());
168 }
169}