Comparar commits

..

2 Commits

  1. 3
      changelog/entries/Add "cl status".md
  2. 106
      src/action_pack.rs
  3. 14
      src/action_status.rs
  4. 26
      src/main.rs
  5. 28
      src/store.rs

@ -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.

@ -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 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 (channel_detected, channel_explicit) = match channel {
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(())
}

@ -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, _)) => {

@ -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 {

Cargando…
Cancelar
Guardar