Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 79 additions & 20 deletions src/monorepo/run/cascade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::versioning::compute_next_version;
use super::super::types::CheckPackage;
use super::super::util::tags_for_package;
use super::super::version_source::VersionSource;
use super::plan::with_prerelease_suffix;
use super::release_json::ReleasedPackage;
use super::summary::PlannedTag;
use super::version_hook::{Candidate, Resolved};
Expand All @@ -37,13 +38,7 @@ pub(super) fn run_dependency_cascade(
sink: &mut CascadeSink<'_>,
captured_metadata: &mut std::collections::HashMap<String, String>,
) -> anyhow::Result<()> {
let (config, root, all_tags, channel, dry_run) = (
pass.config,
pass.root,
pass.all_tags,
pass.channel,
pass.dry_run,
);
let (config, root, channel, dry_run) = (pass.config, pass.root, pass.channel(), pass.dry_run);
let settled = settle(config, sink.bumped);
// These packages were not in `bump_order`, so `capture` never saw them and
// their commands are missing from the map. Without this they released with
Expand All @@ -61,9 +56,7 @@ pub(super) fn run_dependency_cascade(
.collect();
super::build_metadata::capture_more(config, &cascaded, root, dry_run, captured_metadata)?;
for (pkg_idx, bump) in settled.order {
let Some(mut release) =
resolve_cascaded(config, root, all_tags, &settled.state, pkg_idx, bump)
else {
let Some(mut release) = resolve_cascaded(pass, &settled.state, pkg_idx, bump) else {
continue;
};
if !release.settle(pass)? {
Expand Down Expand Up @@ -92,16 +85,16 @@ struct CascadedRelease<'a> {
tag: String,
dep_trigger: Vec<&'a str>,
version_pending: bool,
is_prerelease: bool,
}

fn resolve_cascaded<'a>(
config: &'a Config,
root: &Path,
all_tags: &[String],
pass: &super::version_hook::Pass<'a>,
state: &HashMap<String, BumpType>,
pkg_idx: usize,
bump: BumpType,
) -> Option<CascadedRelease<'a>> {
let (config, root, all_tags) = (pass.config, pass.root, pass.all_tags);
let pkg = &config.packages[pkg_idx];
let vf = pkg.versioned_files.first()?;
let current_version = read_version(vf, root).ok()?;
Expand All @@ -110,8 +103,16 @@ fn resolve_cascaded<'a>(
tags_for_package(all_tags, &pkg_tag_prefix)
});
let version_template = pkg.effective_version_template(&config.workspace);
let new_version =
let base_version =
compute_next_version(&current_version, bump, strategy, version_template).ok()?;
let (new_version, is_prerelease) = with_prerelease_suffix(
pkg,
config,
pass.prerelease_ctx,
all_tags,
pass.short_hash,
base_version,
);
if current_version == new_version {
return None;
}
Expand All @@ -135,6 +136,7 @@ fn resolve_cascaded<'a>(
tag,
dep_trigger,
version_pending: false,
is_prerelease,
})
}

Expand All @@ -145,7 +147,7 @@ impl CascadedRelease<'_> {
current: &self.current_version,
proposed: &self.new_version,
bump: self.bump,
is_prerelease: false,
is_prerelease: self.is_prerelease,
commits: &[],
})?;
Ok(match resolved {
Expand Down Expand Up @@ -177,7 +179,7 @@ impl CascadedRelease<'_> {
bump_type: self.bump.to_string(),
tag: self.tag.clone(),
commit_count: 0,
prerelease: false,
prerelease: self.is_prerelease,
version_source: self.version_source(),
forge_release_url: None,
forge_release_id: None,
Expand All @@ -192,7 +194,7 @@ impl CascadedRelease<'_> {
bump_type: self.bump.to_string(),
tag: (!self.version_pending).then(|| self.tag.clone()),
channel: channel.map(str::to_string),
prerelease: false,
prerelease: self.is_prerelease,
version_source: self.version_source(),
commits: vec![],
}
Expand All @@ -211,7 +213,7 @@ impl CascadedRelease<'_> {
package: pkg.name.clone(),
version: self.new_version.clone(),
commit_count: 0,
is_prerelease: false,
is_prerelease: self.is_prerelease,
});
sink.bumped.insert(pkg.name.clone(), self.bump);
sink.bumped_versions
Expand Down Expand Up @@ -416,6 +418,7 @@ fn push_once(files: &mut Vec<String>, path: &str) {
mod tests {
use super::super::version_hook::Pass;
use super::*;
use crate::prerelease::PrereleaseContext;

fn workspace() -> tempfile::TempDir {
let dir = tempfile::tempdir().unwrap();
Expand Down Expand Up @@ -579,7 +582,8 @@ mod tests {
config: &config,
root: dir.path(),
all_tags: &[],
channel: None,
prerelease_ctx: &PrereleaseContext::resolve(None, "main", None).unwrap(),
short_hash: "deadbee",
dry_run: false,
run_commands: false,
},
Expand Down Expand Up @@ -635,7 +639,8 @@ mod tests {
config: &config,
root: dir.path(),
all_tags: &[],
channel: None,
prerelease_ctx: &PrereleaseContext::resolve(None, "main", None).unwrap(),
short_hash: "deadbee",
dry_run: true,
run_commands: false,
},
Expand All @@ -654,6 +659,60 @@ mod tests {
);
}

#[test]
fn a_cascade_in_a_prerelease_run_stays_a_prerelease() {
let dir = workspace();
let config = Config::load(dir.path(), None).unwrap();
let prerelease_ctx = PrereleaseContext::resolve(Some("beta"), "main", None).unwrap();
let all_tags = vec!["cli@v1.1.0-beta.1".to_string()];

let mut any_bumped = false;
let mut json_packages = Vec::new();
let mut released = Vec::new();
let mut files_to_commit = Vec::new();
let mut files_per_package = HashMap::new();
let mut tags_to_create = Vec::new();
let mut pkg_outputs = Vec::new();
let mut bumped = HashMap::from([("core".to_string(), BumpType::Minor)]);
let mut bumped_versions = HashMap::from([("core".to_string(), "1.1.0-beta.1".to_string())]);
let mut sink = CascadeSink {
any_bumped: &mut any_bumped,
json_packages: &mut json_packages,
released: &mut released,
files_to_commit: &mut files_to_commit,
files_per_package: &mut files_per_package,
tags_to_create: &mut tags_to_create,
pkg_outputs: &mut pkg_outputs,
bumped: &mut bumped,
bumped_versions: &mut bumped_versions,
};

run_dependency_cascade(
&Pass {
config: &config,
root: dir.path(),
all_tags: &all_tags,
prerelease_ctx: &prerelease_ctx,
short_hash: "deadbee",
dry_run: true,
run_commands: false,
},
false,
false,
&mut sink,
&mut std::collections::HashMap::new(),
)
.unwrap();

let cli = tags_to_create
.iter()
.find(|t| t.package == "cli")
.expect("cli should be cascaded");
assert_eq!(cli.version, "1.1.0-beta.2");
assert!(cli.is_prerelease);
assert_eq!(bumped_versions.get("cli").unwrap(), "1.1.0-beta.2");
}

#[test]
fn a_dependent_that_opts_out_of_the_cascade_keeps_its_constraint() {
let dir = workspace();
Expand Down
3 changes: 2 additions & 1 deletion src/monorepo/run/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ fn version_pass<'a>(
config,
root,
all_tags: &inputs.all_tags,
channel: inputs.prerelease_ctx.channel.as_deref(),
prerelease_ctx: &inputs.prerelease_ctx,
short_hash: &inputs.short_hash,
dry_run: flags.dry_run,
run_commands: flags.version_commands,
}
Expand Down
26 changes: 15 additions & 11 deletions src/monorepo/run/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,14 @@ pub(super) fn compute_plan(

let base_version =
compute_next_version(&current_version, bump, pkg_strategy, version_template)?;
let (new_version, is_prerelease) = with_prerelease_suffix(pkg, inputs, base_version);
let (new_version, is_prerelease) = with_prerelease_suffix(
pkg,
inputs.config,
inputs.prerelease_ctx,
inputs.all_tags,
inputs.short_hash,
base_version,
);

(new_version, is_prerelease, commits, bump)
};
Expand Down Expand Up @@ -479,22 +486,19 @@ fn resolve_current_version(
Ok((current_version, last_tag, source))
}

fn with_prerelease_suffix(
pub(super) fn with_prerelease_suffix(
pkg: &PackageConfig,
inputs: &PlanInputs<'_>,
config: &Config,
prerelease_ctx: &PrereleaseContext,
all_tags: &[String],
short_hash: &str,
base_version: String,
) -> (String, bool) {
if !inputs.prerelease_ctx.is_prerelease() {
if !prerelease_ctx.is_prerelease() {
return (base_version, false);
}
let config = inputs.config;
let tag_prefix = pkg.tag_prefix(&config.workspace, config.is_monorepo());
match inputs.prerelease_ctx.compute_identifier(
&base_version,
&tag_prefix,
inputs.all_tags,
inputs.short_hash,
) {
match prerelease_ctx.compute_identifier(&base_version, &tag_prefix, all_tags, short_hash) {
Some(resolved) => (format!("{base_version}{}", resolved.full_suffix), true),
None => (base_version, false),
}
Expand Down
10 changes: 8 additions & 2 deletions src/monorepo/run/version_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::changelog::GitLog;
use crate::config::{Config, PackageConfig, VersioningStrategy};
use crate::conventional_commits::BumpType;
use crate::hooks::{HookCommit, HookContext, capture_version};
use crate::prerelease::PrereleaseContext;

use super::super::util::tags_for_package;
use super::plan::{PackagePlan, SkipReason};
Expand Down Expand Up @@ -139,12 +140,17 @@ pub(super) struct Pass<'a> {
pub config: &'a Config,
pub root: &'a Path,
pub all_tags: &'a [String],
pub channel: Option<&'a str>,
pub prerelease_ctx: &'a PrereleaseContext,
pub short_hash: &'a str,
pub dry_run: bool,
pub run_commands: bool,
}

impl Pass<'_> {
pub(super) fn channel(&self) -> Option<&str> {
self.prerelease_ctx.channel.as_deref()
}

pub(super) fn resolve(&self, candidate: &Candidate<'_>) -> Result<Resolved> {
let Some(command) = candidate
.pkg
Expand All @@ -165,7 +171,7 @@ impl Pass<'_> {
proposed: candidate.proposed,
bump: candidate.bump,
is_prerelease: candidate.is_prerelease,
channel: self.channel,
channel: self.channel(),
dry_run: self.dry_run,
commits: candidate.commits,
})?;
Expand Down
Loading