cargo_release/steps/
owner.rs1use crate::error::CliError;
2use crate::ops::git;
3use crate::steps::plan;
4
5#[derive(Debug, Clone, clap::Args)]
7pub struct OwnerStep {
8 #[command(flatten)]
9 manifest: clap_cargo::Manifest,
10
11 #[command(flatten)]
12 workspace: clap_cargo::Workspace,
13
14 #[arg(short, long = "config", value_name = "PATH")]
16 custom_config: Option<std::path::PathBuf>,
17
18 #[arg(long)]
20 isolated: bool,
21
22 #[arg(short = 'Z', value_name = "FEATURE")]
24 z: Vec<crate::config::UnstableValues>,
25
26 #[arg(long, value_delimiter = ',')]
28 allow_branch: Option<Vec<String>>,
29
30 #[arg(short = 'x', long)]
32 execute: bool,
33
34 #[arg(short = 'n', long, conflicts_with = "execute", hide = true)]
35 dry_run: bool,
36
37 #[arg(long)]
39 no_confirm: bool,
40}
41
42impl OwnerStep {
43 pub fn run(&self) -> Result<(), CliError> {
44 git::git_version()?;
45
46 if self.dry_run {
47 let _ =
48 crate::ops::shell::warn("`--dry-run` is superfluous, dry-run is done by default");
49 }
50
51 let ws_meta = self
52 .manifest
53 .metadata()
54 .features(cargo_metadata::CargoOpt::AllFeatures)
56 .exec()?;
57 let config = self.to_config();
58 let ws_config = crate::config::load_workspace_config(&config, &ws_meta)?;
59 let mut pkgs = plan::load(&config, &ws_meta)?;
60
61 let (_selected_pkgs, excluded_pkgs) = self.workspace.partition_packages(&ws_meta);
62 for excluded_pkg in excluded_pkgs {
63 let Some(pkg) = pkgs.get_mut(&excluded_pkg.id) else {
64 continue;
66 };
67 if !pkg.config.release() {
68 continue;
69 }
70
71 pkg.config.publish = Some(false);
72 pkg.config.owners = Some(vec![]);
73 pkg.config.release = Some(false);
74
75 let crate_name = pkg.meta.name.as_str();
76 log::debug!("disabled by user, skipping {crate_name}",);
77 }
78
79 let mut pkgs = plan::plan(pkgs)?;
80
81 for pkg in pkgs.values_mut() {
82 if pkg.config.owners().is_empty() {
83 log::debug!("disabled due to no owners, skipping {}", pkg.meta.name);
84 pkg.config.publish = Some(false);
85 pkg.config.owners = Some(vec![]);
86 pkg.config.release = Some(false);
87 } else if !pkg.config.publish() {
88 log::debug!("disabled due to publish=false, skipping {}", pkg.meta.name);
89 pkg.config.publish = Some(false);
90 pkg.config.owners = Some(vec![]);
91 pkg.config.release = Some(false);
92 }
93 }
94
95 let (selected_pkgs, _excluded_pkgs): (Vec<_>, Vec<_>) = pkgs
96 .into_iter()
97 .map(|(_, pkg)| pkg)
98 .partition(|p| p.config.release());
99 if selected_pkgs.is_empty() {
100 let _ = crate::ops::shell::error("no packages selected");
101 return Err(2.into());
102 }
103
104 let dry_run = !self.execute;
105 let mut failed = false;
106
107 failed |= !super::verify_git_is_clean(
109 ws_meta.workspace_root.as_std_path(),
110 dry_run,
111 log::Level::Error,
112 )?;
113
114 failed |= !super::verify_git_branch(
115 ws_meta.workspace_root.as_std_path(),
116 &ws_config,
117 dry_run,
118 log::Level::Error,
119 )?;
120
121 failed |= !super::verify_if_behind(
122 ws_meta.workspace_root.as_std_path(),
123 &ws_config,
124 dry_run,
125 log::Level::Warn,
126 )?;
127
128 super::confirm("Owner", &selected_pkgs, self.no_confirm, dry_run)?;
130
131 ensure_owners(&selected_pkgs, dry_run)?;
132
133 super::finish(failed, dry_run)
134 }
135
136 fn to_config(&self) -> crate::config::ConfigArgs {
137 crate::config::ConfigArgs {
138 custom_config: self.custom_config.clone(),
139 isolated: self.isolated,
140 z: self.z.clone(),
141 allow_branch: self.allow_branch.clone(),
142 ..Default::default()
143 }
144 }
145}
146
147pub fn ensure_owners(pkgs: &[plan::PackageRelease], dry_run: bool) -> Result<(), CliError> {
148 for pkg in pkgs {
149 if !pkg.config.publish() || !pkg.ensure_owners {
150 continue;
151 }
152
153 let crate_name = pkg.meta.name.as_str();
154 crate::ops::cargo::ensure_owners(
155 crate_name,
156 pkg.config.owners(),
157 pkg.config.registry(),
158 dry_run,
159 )?;
160 }
161
162 Ok(())
163}