diff --git a/cargo-dist/src/backend/ci/github.rs b/cargo-dist/src/backend/ci/github.rs index 26e24167e..d6524d376 100644 --- a/cargo-dist/src/backend/ci/github.rs +++ b/cargo-dist/src/backend/ci/github.rs @@ -302,7 +302,7 @@ impl GithubCiInfo { } let mut publish_jobs = vec![]; - if let Some(PublisherConfig { homebrew, npm }) = &dist.global_publishers { + if let Some(PublisherConfig { homebrew, npm, .. }) = &dist.global_publishers { if homebrew.is_some() { publish_jobs.push(PublishStyle::Homebrew.to_string()); } diff --git a/cargo-dist/src/config/v0_to_v1.rs b/cargo-dist/src/config/v0_to_v1.rs index 6ffb0ef5a..0a04c9cc7 100644 --- a/cargo-dist/src/config/v0_to_v1.rs +++ b/cargo-dist/src/config/v0_to_v1.rs @@ -339,8 +339,12 @@ impl DistMetadata { list_to_bool_layer(is_global, &publish_jobs, PublishStyle::Homebrew, || None); let npm_publisher_layer = list_to_bool_layer(is_global, &publish_jobs, PublishStyle::Npm, || None); + let custom_layer = list_to_bool_layer_predicate(is_global, &publish_jobs, |job| { + matches!(job, PublishStyle::User(_)) + }); let needs_publisher_layer = homebrew_publisher_layer.is_some() || npm_publisher_layer.is_some() + || custom_layer.is_some() || publish_prereleases.is_some(); let publisher_layer = needs_publisher_layer.then_some(PublisherLayer { common: CommonPublisherLayer { @@ -348,6 +352,7 @@ impl DistMetadata { }, homebrew: homebrew_publisher_layer, npm: npm_publisher_layer, + custom: custom_layer, }); // done! @@ -394,3 +399,25 @@ where Some(BoolOr::Bool(is_in_list)) } } + +fn list_to_bool_layer_predicate( + is_global: bool, + list: &Option>, + predicate: impl FnMut(&&I) -> bool, +) -> Option> +where + I: Eq, +{ + // If the list doesn't exist, don't mention it + let list = list.as_ref()?; + // Otherwise treat "is in the list" as a simple boolean + let is_in_list = list.iter().find(predicate).is_some(); + if is_global && !is_in_list { + // ... with the exception of an omitted value in the global list. + // here None and Some(false) are the same, so Some(false) is Noise + // we want to hide. + None + } else { + Some(BoolOr::Bool(is_in_list)) + } +} diff --git a/cargo-dist/src/config/v1/publishers/custom.rs b/cargo-dist/src/config/v1/publishers/custom.rs new file mode 100644 index 000000000..cb603ec2f --- /dev/null +++ b/cargo-dist/src/config/v1/publishers/custom.rs @@ -0,0 +1,49 @@ +//! custom publisher config + +use super::*; + +/// Options for custom publishes +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct CustomPublisherLayer { + /// Common options + pub common: CommonPublisherLayer, +} +/// Options for custom publishes +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct CustomPublisherConfig { + /// Common options + pub common: CommonPublisherConfig, +} + +impl CustomPublisherConfig { + /// Get defaults for the given package + pub fn defaults_for_package( + _workspaces: &WorkspaceGraph, + _pkg_idx: PackageIdx, + common: &CommonPublisherConfig, + ) -> Self { + Self { + common: common.clone(), + } + } +} + +impl ApplyLayer for CustomPublisherConfig { + type Layer = CustomPublisherLayer; + fn apply_layer(&mut self, Self::Layer { common }: Self::Layer) { + self.common.apply_layer(common); + } +} +impl ApplyLayer for CustomPublisherLayer { + type Layer = CustomPublisherLayer; + fn apply_layer(&mut self, Self::Layer { common }: Self::Layer) { + self.common.apply_layer(common); + } +} + +impl std::ops::Deref for CustomPublisherConfig { + type Target = CommonPublisherConfig; + fn deref(&self) -> &Self::Target { + &self.common + } +} diff --git a/cargo-dist/src/config/v1/publishers/mod.rs b/cargo-dist/src/config/v1/publishers/mod.rs index 6ad4abf0d..2209facc8 100644 --- a/cargo-dist/src/config/v1/publishers/mod.rs +++ b/cargo-dist/src/config/v1/publishers/mod.rs @@ -1,10 +1,12 @@ //! publisher config +pub mod custom; pub mod homebrew; pub mod npm; use super::*; +use custom::*; use homebrew::*; use npm::*; @@ -15,6 +17,8 @@ pub struct PublisherConfig { pub homebrew: Option, /// npm publisher pub npm: Option, + /// custom publish jobs + pub custom: Option, } /// the publisher config @@ -28,6 +32,8 @@ pub struct PublisherConfigInheritable { pub homebrew: Option, /// npm publisher pub npm: Option, + /// custom publisher + pub custom: Option, } /// "raw" publisher config from presum @@ -40,6 +46,8 @@ pub struct PublisherLayer { pub homebrew: Option>, /// npm publisher pub npm: Option>, + /// custom publisher + pub custom: Option>, } impl PublisherConfigInheritable { /// get the defaults for a given package @@ -48,6 +56,7 @@ impl PublisherConfigInheritable { common: CommonPublisherConfig::defaults_for_package(workspaces, pkg_idx), homebrew: None, npm: None, + custom: None, } } /// fold the inherited fields in to get the final publisher config @@ -60,6 +69,7 @@ impl PublisherConfigInheritable { common, homebrew, npm, + custom, } = self; let homebrew = homebrew.map(|homebrew| { let mut default = @@ -73,7 +83,17 @@ impl PublisherConfigInheritable { default.apply_layer(npm); default }); - PublisherConfig { homebrew, npm } + let custom = custom.map(|custom| { + let mut default = + CustomPublisherConfig::defaults_for_package(workspaces, pkg_idx, &common); + default.apply_layer(custom); + default + }); + PublisherConfig { + homebrew, + npm, + custom, + } } } impl ApplyLayer for PublisherConfigInheritable { @@ -84,11 +104,13 @@ impl ApplyLayer for PublisherConfigInheritable { common, homebrew, npm, + custom, }: Self::Layer, ) { self.common.apply_layer(common); self.homebrew.apply_bool_layer(homebrew); self.npm.apply_bool_layer(npm); + self.custom.apply_bool_layer(custom); } } diff --git a/cargo-dist/src/tasks.rs b/cargo-dist/src/tasks.rs index 187df1c6b..3dda3f75e 100644 --- a/cargo-dist/src/tasks.rs +++ b/cargo-dist/src/tasks.rs @@ -1140,10 +1140,15 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> { .as_ref() .map(|p| { // until we have `dist publish` we need to enforce everyone agreeing on `prereleases` - let PublisherConfig { homebrew, npm } = p; + let PublisherConfig { + homebrew, + npm, + custom, + } = p; let h_pre = homebrew.as_ref().map(|p| p.prereleases); let npm_pre = npm.as_ref().map(|p| p.prereleases); - let choices = [h_pre, npm_pre]; + let custom_pre = custom.as_ref().map(|p| p.prereleases); + let choices = [h_pre, npm_pre, custom_pre]; let mut global_choice = None; #[allow(clippy::manual_flatten)] for choice in choices {