add cl status, improve cl pack
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# New features
|
||||
- Add command line option `cl status` (#SW-4716)
|
||||
- Change `cl pack` to show a preview of the rendered changelog before asking for version.
|
||||
+65
-41
@@ -1,21 +1,56 @@
|
||||
use crate::AppContext;
|
||||
use crate::config::ChannelName;
|
||||
use crate::git::get_branch_name;
|
||||
use crate::git::{BranchName, get_branch_name};
|
||||
use crate::store::{Release, Store};
|
||||
use anyhow::bail;
|
||||
use colored::Colorize;
|
||||
|
||||
/// Perform the action of packing changelog entries for a release
|
||||
pub(crate) fn cl_pack(ctx: AppContext, channel: Option<ChannelName>) -> anyhow::Result<()> {
|
||||
let mut store = Store::new(&ctx, false)?;
|
||||
let branch = get_branch_name(&ctx);
|
||||
pub fn pack_resolve_and_show_preview(
|
||||
ctx: &AppContext,
|
||||
user_chosen_channel: Option<ChannelName>,
|
||||
branch: Option<&BranchName>,
|
||||
) -> anyhow::Result<Option<(Release, ChannelName)>> {
|
||||
let channel = resolve_channel(&ctx, user_chosen_channel, branch)?;
|
||||
let store = Store::new(&ctx, false)?;
|
||||
|
||||
let (channel_detected, channel_explicit) = match channel {
|
||||
let unreleased = store.find_unreleased_changes(&channel)?;
|
||||
|
||||
if unreleased.is_empty() {
|
||||
eprintln!("No unreleased changes.");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Changes waiting for release:");
|
||||
for entry in &unreleased {
|
||||
println!("+ {}", entry.cyan());
|
||||
}
|
||||
println!();
|
||||
|
||||
let release = Release {
|
||||
version: "Unreleased".to_string(),
|
||||
entries: unreleased,
|
||||
};
|
||||
|
||||
let rendered = store.render_release(&release)?;
|
||||
|
||||
println!("\nPreview:\n\n{}", rendered);
|
||||
|
||||
Ok(Some((release, channel)))
|
||||
}
|
||||
|
||||
/// Resolve channel from current branch or other context info, ask if needed
|
||||
fn resolve_channel(
|
||||
ctx: &AppContext,
|
||||
user_chosen_channel: Option<ChannelName>,
|
||||
branch: Option<&BranchName>,
|
||||
) -> anyhow::Result<ChannelName> {
|
||||
let (channel_detected, channel_explicit) = match user_chosen_channel {
|
||||
Some(ch) => (Some(ch), true), // passed via flag already
|
||||
None => (
|
||||
branch
|
||||
.as_ref()
|
||||
.map(|b| b.parse_channel(&ctx))
|
||||
.map(|b| b.parse_channel(ctx))
|
||||
.transpose()?
|
||||
.flatten(),
|
||||
false,
|
||||
@@ -28,22 +63,6 @@ pub(crate) fn cl_pack(ctx: AppContext, channel: Option<ChannelName>) -> anyhow::
|
||||
bail!("No such channel: {ch}");
|
||||
}
|
||||
|
||||
// If the branch is named rel/3.40, this can extract 3.40.
|
||||
// TODO try to get something better from git!
|
||||
let version_base = branch
|
||||
.as_ref()
|
||||
.map(|b| b.parse_version(&ctx))
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
// TODO detect version from git query?
|
||||
|
||||
// TODO remove this
|
||||
eprintln!(
|
||||
"Branch name: {:?}, channel: {:?}, version: {:?}",
|
||||
branch, channel_detected, version_base
|
||||
);
|
||||
|
||||
// Ask for the channel
|
||||
let channel = if ctx.config.channels.len() > 1 {
|
||||
if channel_explicit {
|
||||
@@ -66,19 +85,31 @@ pub(crate) fn cl_pack(ctx: AppContext, channel: Option<ChannelName>) -> anyhow::
|
||||
};
|
||||
println!("Channel: {}", channel.green().bold());
|
||||
|
||||
let unreleased = store.find_unreleased_changes(&channel)?;
|
||||
Ok(channel)
|
||||
}
|
||||
|
||||
if unreleased.is_empty() {
|
||||
eprintln!("No unreleased changes.");
|
||||
/// Perform the action of packing changelog entries for a release
|
||||
pub(crate) fn cl_pack(
|
||||
ctx: AppContext,
|
||||
user_chosen_channel: Option<ChannelName>,
|
||||
) -> anyhow::Result<()> {
|
||||
let branch = get_branch_name(&ctx);
|
||||
let Some((mut release, channel)) =
|
||||
pack_resolve_and_show_preview(&ctx, user_chosen_channel, branch.as_ref())?
|
||||
else {
|
||||
// No changes
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
println!();
|
||||
println!("Changes waiting for release:");
|
||||
for entry in &unreleased {
|
||||
println!("+ {}", entry.cyan());
|
||||
}
|
||||
println!();
|
||||
let mut store = Store::new(&ctx, false)?;
|
||||
|
||||
// If the branch is named rel/3.40, this can extract 3.40.
|
||||
// TODO try to get something better from git!
|
||||
let version_base = branch
|
||||
.as_ref()
|
||||
.map(|b| b.parse_version(&ctx))
|
||||
.transpose()?
|
||||
.flatten();
|
||||
|
||||
// Ask for the version
|
||||
let mut version = version_base.unwrap_or_default();
|
||||
@@ -99,14 +130,7 @@ pub(crate) fn cl_pack(ctx: AppContext, channel: Option<ChannelName>) -> anyhow::
|
||||
}
|
||||
}
|
||||
|
||||
let release = Release {
|
||||
version,
|
||||
entries: unreleased,
|
||||
};
|
||||
|
||||
let rendered = store.render_release(&release)?;
|
||||
|
||||
println!("\n\nPreview:\n\n{}\n", rendered);
|
||||
release.version = version;
|
||||
|
||||
if !inquire::Confirm::new("Continue - write to changelog file?")
|
||||
.with_default(true)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
use crate::AppContext;
|
||||
use crate::action_pack::pack_resolve_and_show_preview;
|
||||
use crate::config::ChannelName;
|
||||
use crate::git::{get_branch_name};
|
||||
|
||||
/// Perform the action of packing changelog entries for a release
|
||||
pub(crate) fn cl_status(
|
||||
ctx: AppContext,
|
||||
user_chosen_channel: Option<ChannelName>,
|
||||
) -> anyhow::Result<()> {
|
||||
let branch = get_branch_name(&ctx);
|
||||
pack_resolve_and_show_preview(&ctx, user_chosen_channel, branch.as_ref())?;
|
||||
Ok(())
|
||||
}
|
||||
+20
-6
@@ -1,6 +1,7 @@
|
||||
use crate::action_init::{cl_init, ClInit};
|
||||
use crate::action_init::{ClInit, cl_init};
|
||||
use crate::action_log::cl_log;
|
||||
use crate::action_pack::cl_pack;
|
||||
use crate::action_status::cl_status;
|
||||
use crate::config::{ChannelName, Config};
|
||||
use anyhow::bail;
|
||||
use clap::builder::NonEmptyStringValueParser;
|
||||
@@ -17,6 +18,8 @@ mod action_pack;
|
||||
|
||||
mod action_init;
|
||||
|
||||
mod action_status;
|
||||
|
||||
mod store;
|
||||
|
||||
mod utils;
|
||||
@@ -47,6 +50,12 @@ fn main_try() -> anyhow::Result<()> {
|
||||
.flatten()
|
||||
.unwrap_or_else(|| "cl".to_string());
|
||||
|
||||
let optional_channel_arg = clap::Arg::new("CHANNEL")
|
||||
.short('x')
|
||||
.long("channel")
|
||||
.value_parser(NonEmptyStringValueParser::new())
|
||||
.required(false);
|
||||
|
||||
let args = clap::Command::new(&binary_name)
|
||||
.version(env!("CARGO_PKG_VERSION"))
|
||||
.author(env!("CARGO_PKG_AUTHORS"))
|
||||
@@ -57,11 +66,12 @@ fn main_try() -> anyhow::Result<()> {
|
||||
clap::Command::new("pack")
|
||||
.visible_alias("release")
|
||||
.about("Pack changelog entries to a changelog section")
|
||||
.arg(clap::Arg::new("CHANNEL")
|
||||
.short('x')
|
||||
.long("channel")
|
||||
.value_parser(NonEmptyStringValueParser::new())
|
||||
.required(false)),
|
||||
.arg(optional_channel_arg.clone()),
|
||||
)
|
||||
.subcommand(
|
||||
clap::Command::new("status")
|
||||
.about("Show outstanding change entries on the current channel (or specified channel)")
|
||||
.arg(optional_channel_arg),
|
||||
)
|
||||
.subcommand(clap::Command::new("add")
|
||||
.visible_alias("log")
|
||||
@@ -133,6 +143,10 @@ fn main_try() -> anyhow::Result<()> {
|
||||
let channel: Option<ChannelName> = subargs.get_one("CHANNEL").cloned();
|
||||
cl_pack(ctx, channel)?;
|
||||
}
|
||||
Some(("status", subargs)) => {
|
||||
let channel: Option<ChannelName> = subargs.get_one("CHANNEL").cloned();
|
||||
cl_status(ctx, channel)?;
|
||||
}
|
||||
None | Some(("add", _)) => cl_log(ctx)?,
|
||||
// TODO: status, flush
|
||||
Some((other, _)) => {
|
||||
|
||||
+19
-9
@@ -382,22 +382,32 @@ struct ChannelReleaseStore {
|
||||
impl ChannelReleaseStore {
|
||||
/// Load from a versions file
|
||||
fn load(releases_file: PathBuf, channel_name: ChannelName) -> anyhow::Result<Self> {
|
||||
println!(
|
||||
"Loading versions for channel {} from: {}",
|
||||
channel_name,
|
||||
releases_file.display()
|
||||
);
|
||||
let releases = if !releases_file.exists() {
|
||||
// File did not exist yet, create it - this catches error with write access early
|
||||
let mut f = OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&releases_file)?;
|
||||
f.write_all("[]".as_bytes())?;
|
||||
.open(&releases_file)
|
||||
.with_context(|| {
|
||||
format!("Failed to open channel file: {}", releases_file.display())
|
||||
})?;
|
||||
f.write_all("[]".as_bytes()).with_context(|| {
|
||||
format!(
|
||||
"Failed to write into channel file: {}",
|
||||
releases_file.display()
|
||||
)
|
||||
})?;
|
||||
Default::default()
|
||||
} else {
|
||||
let channel_json = read_to_string(&releases_file)?;
|
||||
serde_json::from_str::<ReleaseList>(&channel_json)?
|
||||
let channel_json = read_to_string(&releases_file).with_context(|| {
|
||||
format!("Failed to read channel file: {}", releases_file.display())
|
||||
})?;
|
||||
serde_json::from_str::<ReleaseList>(&channel_json).with_context(|| {
|
||||
format!(
|
||||
"Failed to parse content of channel file: {}",
|
||||
releases_file.display()
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
|
||||
Reference in New Issue
Block a user