implement changelog packing, more config options, better formatting & flexibility
This commit is contained in:
Generated
+225
-1
@@ -11,6 +11,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.20"
|
||||
@@ -85,18 +94,47 @@ version = "2.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65193589c6404eb80b450d618eaf9a2cafaaafd57ecce47370519ef674a7bd44"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.47"
|
||||
@@ -129,6 +167,7 @@ name = "clpack"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"faccess",
|
||||
@@ -156,6 +195,12 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.25.0"
|
||||
@@ -220,6 +265,12 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d"
|
||||
|
||||
[[package]]
|
||||
name = "fuzzy-matcher"
|
||||
version = "0.3.7"
|
||||
@@ -256,6 +307,30 @@ version = "0.15.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.11.1"
|
||||
@@ -296,6 +371,16 @@ version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.175"
|
||||
@@ -351,6 +436,15 @@ dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
@@ -461,6 +555,12 @@ dependencies = [
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
@@ -514,6 +614,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.18"
|
||||
@@ -707,6 +813,65 @@ dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -729,12 +894,71 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link 0.2.0",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
|
||||
dependencies = [
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
|
||||
dependencies = [
|
||||
"windows-link 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
@@ -790,7 +1014,7 @@ version = "0.53.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.1.3",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
||||
@@ -16,6 +16,7 @@ regex = "1"
|
||||
anyhow = "1"
|
||||
colored = "3"
|
||||
faccess = "0.2"
|
||||
chrono = "0.4"
|
||||
|
||||
# input
|
||||
|
||||
|
||||
+55
-24
@@ -1,19 +1,32 @@
|
||||
use crate::AppContext;
|
||||
use crate::config::ChannelName;
|
||||
use crate::git::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) -> anyhow::Result<()> {
|
||||
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);
|
||||
|
||||
let channel_detected = branch
|
||||
.as_ref()
|
||||
.map(|b| b.parse_channel(&ctx))
|
||||
.transpose()?
|
||||
.flatten();
|
||||
let (channel_detected, channel_explicit) = match channel {
|
||||
Some(ch) => (Some(ch), true), // passed via flag already
|
||||
None => (
|
||||
branch
|
||||
.as_ref()
|
||||
.map(|b| b.parse_channel(&ctx))
|
||||
.transpose()?
|
||||
.flatten(),
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
if let Some(ch) = &channel_detected
|
||||
&& !ctx.config.channels.contains_key(ch)
|
||||
{
|
||||
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!
|
||||
@@ -33,16 +46,20 @@ pub(crate) fn cl_pack(ctx: AppContext) -> anyhow::Result<()> {
|
||||
|
||||
// Ask for the channel
|
||||
let channel = if ctx.config.channels.len() > 1 {
|
||||
let channels = ctx.config.channels.values().collect::<Vec<_>>();
|
||||
let mut starting_index = None;
|
||||
if let Some(channel) = channel_detected {
|
||||
starting_index = channels.iter().position(|ch| *ch == &channel);
|
||||
if channel_explicit {
|
||||
channel_detected.unwrap()
|
||||
} else {
|
||||
let channels = ctx.config.channels.keys().collect::<Vec<_>>();
|
||||
let mut starting_index = None;
|
||||
if let Some(channel) = channel_detected {
|
||||
starting_index = channels.iter().position(|ch| *ch == &channel);
|
||||
}
|
||||
let mut query = inquire::Select::new("Release channel?", channels);
|
||||
if let Some(index) = starting_index {
|
||||
query = query.with_starting_cursor(index);
|
||||
}
|
||||
query.prompt()?.to_string()
|
||||
}
|
||||
let mut query = inquire::Select::new("Release channel?", channels);
|
||||
if let Some(index) = starting_index {
|
||||
query = query.with_starting_cursor(index);
|
||||
}
|
||||
query.prompt()?.to_string()
|
||||
} else {
|
||||
// Just one channel, so use that
|
||||
ctx.config.default_channel.clone()
|
||||
@@ -57,9 +74,9 @@ pub(crate) fn cl_pack(ctx: AppContext) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("Changes waiting for release:\n");
|
||||
println!("Changes waiting for release:");
|
||||
for entry in &unreleased {
|
||||
println!("+ {entry}\n");
|
||||
println!("+ {}", entry.cyan());
|
||||
}
|
||||
println!();
|
||||
|
||||
@@ -82,11 +99,25 @@ pub(crate) fn cl_pack(ctx: AppContext) -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
store.create_release(
|
||||
channel,
|
||||
Release {
|
||||
version,
|
||||
entries: unreleased,
|
||||
},
|
||||
)
|
||||
let release = Release {
|
||||
version,
|
||||
entries: unreleased,
|
||||
};
|
||||
|
||||
let rendered = store.render_release(&release)?;
|
||||
|
||||
println!("\n\nPreview:\n\n{}\n", rendered);
|
||||
|
||||
if !inquire::Confirm::new("Continue - write to changelog file?")
|
||||
.with_default(true)
|
||||
.prompt()?
|
||||
{
|
||||
eprintln!("{}", "Cancelled.".red());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
store.create_release(channel, release)?;
|
||||
|
||||
println!("{}", "Changelog written.".green());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+10
-1
@@ -37,10 +37,19 @@ pub struct Config {
|
||||
/// - `{channel}`, `{Channel}`, `{CHANNEL}` - Channel ID in the respective capitalization
|
||||
#[default = "CHANGELOG-{CHANNEL}.md"]
|
||||
pub changelog_file_channel: String,
|
||||
|
||||
|
||||
/// Title of the changelog file, stripped and put back in front
|
||||
#[default = "# Changelog\n\n"]
|
||||
pub changelog_header: String,
|
||||
|
||||
/// Pattern for release header
|
||||
#[default = "[{VERSION}] - {DATE}"]
|
||||
pub release_header: String,
|
||||
|
||||
/// Date format (see patterns supported by the Chrono crate: https://docs.rs/chrono/latest/chrono/format/strftime/index.html )
|
||||
#[default = "%Y-%m-%d"]
|
||||
pub date_format: String,
|
||||
|
||||
/// Changelog sections suggested when creating a new entry.
|
||||
///
|
||||
/// Users may also specify a custom section name.
|
||||
|
||||
@@ -98,6 +98,10 @@ impl BranchName {
|
||||
/// Try to detect a release channel from this branch name (e.g. stable, EAP)
|
||||
pub fn parse_channel(&self, ctx: &AppContext) -> anyhow::Result<Option<String>> {
|
||||
for (channel_id, template) in &ctx.config.channels {
|
||||
if template.is_empty() {
|
||||
// Channel only for manual choosing
|
||||
continue;
|
||||
}
|
||||
if let Some(pat_s) = as_regex_pattern(template) {
|
||||
let pat = match regex::Regex::new(pat_s) {
|
||||
Ok(pat) => pat,
|
||||
|
||||
+15
-9
@@ -1,7 +1,7 @@
|
||||
use crate::action_init::{ClInit, cl_init};
|
||||
use crate::action_log::cl_log;
|
||||
use crate::action_pack::cl_pack;
|
||||
use crate::config::Config;
|
||||
use crate::config::{ChannelName, Config};
|
||||
use anyhow::bail;
|
||||
use clap::builder::NonEmptyStringValueParser;
|
||||
use colored::Colorize;
|
||||
@@ -33,7 +33,7 @@ pub struct AppContext {
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = main_try() {
|
||||
eprintln!("{}", e.to_string().red().bold());
|
||||
eprintln!("{}", format!("{:?}", e).red().bold());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -54,15 +54,20 @@ fn main_try() -> anyhow::Result<()> {
|
||||
.subcommand(
|
||||
clap::Command::new("pack")
|
||||
.visible_alias("release")
|
||||
.about("Pack changelog entries to a changelog section"),
|
||||
.about("Pack changelog entries to a changelog section")
|
||||
.arg(clap::Arg::new("CHANNEL")
|
||||
.short('x')
|
||||
.long("channel")
|
||||
.value_parser(NonEmptyStringValueParser::new())
|
||||
.required(false)),
|
||||
)
|
||||
.subcommand(clap::Command::new("add")
|
||||
.visible_alias("log")
|
||||
.about("Add a changelog entry on the current branch"))
|
||||
.subcommand(clap::Command::new("flush")
|
||||
.about("Remove all changelog entries that were already released on all channels - clean up the changelog dir. Use e.g. when making a major release where all channel branches are merged."))
|
||||
.subcommand(clap::Command::new("status")
|
||||
.about("Show changelog entries currently waiting for release on the current channel"))
|
||||
// .subcommand(clap::Command::new("flush")
|
||||
// .about("Remove all changelog entries that were already released on all channels - clean up the changelog dir. Use e.g. when making a major release where all channel branches are merged."))
|
||||
// .subcommand(clap::Command::new("status")
|
||||
// .about("Show changelog entries currently waiting for release on the current channel"))
|
||||
.subcommand_required(false)
|
||||
.arg(clap::Arg::new("CONFIG")
|
||||
.short('c')
|
||||
@@ -122,8 +127,9 @@ fn main_try() -> anyhow::Result<()> {
|
||||
// eprintln!("AppCtx: {:?}", ctx);
|
||||
|
||||
match args.subcommand() {
|
||||
Some(("pack", _)) => {
|
||||
cl_pack(ctx)?;
|
||||
Some(("pack", subargs)) => {
|
||||
let channel: Option<ChannelName> = subargs.get_one("CHANNEL").cloned();
|
||||
cl_pack(ctx, channel)?;
|
||||
}
|
||||
None | Some(("add", _)) => cl_log(ctx)?,
|
||||
// TODO: status, flush
|
||||
|
||||
+50
-28
@@ -1,5 +1,5 @@
|
||||
use crate::AppContext;
|
||||
use crate::config::{ChannelName, EntryName, VersionName};
|
||||
use crate::config::{ChannelName, Config, EntryName, VersionName};
|
||||
use anyhow::bail;
|
||||
use colored::Colorize;
|
||||
use faccess::PathExt;
|
||||
@@ -92,8 +92,8 @@ impl<'a> Store<'a> {
|
||||
|
||||
/// Check and create internal subdirs for the clpack system
|
||||
pub fn ensure_internal_subdirs_exist(&self) -> anyhow::Result<()> {
|
||||
self.ensure_subdir_exists(DIR_ENTRIES)?;
|
||||
self.ensure_subdir_exists(DIR_CHANNELS)?;
|
||||
self.ensure_subdir_exists(DIR_ENTRIES, true)?;
|
||||
self.ensure_subdir_exists(DIR_CHANNELS, false)?;
|
||||
// TODO
|
||||
|
||||
Ok(())
|
||||
@@ -102,7 +102,7 @@ impl<'a> Store<'a> {
|
||||
/// make sure a subdir exists, creating if needed.
|
||||
///
|
||||
/// Note there is no lock so there can be a TOCTOU bug later if someone deletes the path - must be checked and handled.
|
||||
fn ensure_subdir_exists(&self, name: &str) -> anyhow::Result<()> {
|
||||
fn ensure_subdir_exists(&self, name: &str, gitkeep: bool) -> anyhow::Result<()> {
|
||||
let subdir = self.store_path.join(name);
|
||||
|
||||
if !subdir.is_dir() {
|
||||
@@ -120,7 +120,9 @@ impl<'a> Store<'a> {
|
||||
bail!("Changelog subdir is not writable: {}", subdir.display());
|
||||
}
|
||||
|
||||
std::fs::File::create(subdir.join(".gitkeep"))?;
|
||||
if gitkeep {
|
||||
std::fs::File::create(subdir.join(".gitkeep"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -157,12 +159,13 @@ impl<'a> Store<'a> {
|
||||
|
||||
/// Create a release entry, write it to the releases buffer and to the file.
|
||||
pub fn create_release(&mut self, channel: ChannelName, release: Release) -> anyhow::Result<()> {
|
||||
let rendered = self.render_release(&release)?;
|
||||
|
||||
let Some(store) = self.versions.get_mut(&channel) else {
|
||||
bail!("Channel {channel} does not exist.");
|
||||
};
|
||||
|
||||
let config = &self.ctx.config;
|
||||
let rendered = release.render(self.store_path.join(DIR_ENTRIES), &config.sections)?;
|
||||
|
||||
let changelog_file = self.ctx.root.join(
|
||||
if channel == config.default_channel {
|
||||
@@ -209,6 +212,12 @@ impl<'a> Store<'a> {
|
||||
store.write_to_file()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Render a release
|
||||
pub fn render_release(&self, release: &Release) -> anyhow::Result<String> {
|
||||
let config = &self.ctx.config;
|
||||
release.render(self.store_path.join(DIR_ENTRIES), &config)
|
||||
}
|
||||
}
|
||||
|
||||
/// Uppercase first char of a string
|
||||
@@ -230,12 +239,8 @@ pub struct Release {
|
||||
}
|
||||
|
||||
impl Release {
|
||||
/// Render the entry into a Markdown fragment, using h2 (##) as the title.
|
||||
pub fn render(
|
||||
&self,
|
||||
entries_dir: impl AsRef<Path>,
|
||||
predefined_sections: &[String],
|
||||
) -> anyhow::Result<String> {
|
||||
/// Render the entry into a Markdown fragment, using h2 (##) as the title, h3 (###) for sections
|
||||
pub fn render(&self, entries_dir: impl AsRef<Path>, config: &Config) -> anyhow::Result<String> {
|
||||
let mut entries_per_section = HashMap::<String, String>::new();
|
||||
let entries_dir = entries_dir.as_ref();
|
||||
let unnamed = "".to_string();
|
||||
@@ -256,6 +261,9 @@ impl Release {
|
||||
let mut current_section = unnamed.clone();
|
||||
for line in reader.lines() {
|
||||
let line = line?;
|
||||
if line.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
if line.trim().starts_with('#') {
|
||||
// It is a section name
|
||||
let section = line.trim_matches(|c| c == '#' || c == ' ');
|
||||
@@ -278,7 +286,7 @@ impl Release {
|
||||
reordered_sections.push(("".to_string(), unlabelled));
|
||||
}
|
||||
|
||||
for section_name in [unnamed].iter().chain(predefined_sections.iter()) {
|
||||
for section_name in [unnamed].iter().chain(config.sections.iter()) {
|
||||
if let Some(content) = entries_per_section.remove(section_name) {
|
||||
reordered_sections.push((section_name.clone(), content));
|
||||
}
|
||||
@@ -288,14 +296,21 @@ impl Release {
|
||||
reordered_sections.push((section_name, content));
|
||||
}
|
||||
|
||||
let mut buffer = String::new();
|
||||
let date = chrono::Local::now();
|
||||
let mut buffer = format!(
|
||||
"## {}\n",
|
||||
config
|
||||
.release_header
|
||||
.replace("{VERSION}", &self.version)
|
||||
.replace("{DATE}", &date.format(&config.date_format).to_string())
|
||||
);
|
||||
|
||||
for (section_name, content) in reordered_sections {
|
||||
if !section_name.is_empty() {
|
||||
buffer.push_str(&format!("## {}\n", section_name));
|
||||
buffer.push_str(&format!("\n### {}\n\n", section_name));
|
||||
}
|
||||
buffer.push_str(&content);
|
||||
buffer.push('\n');
|
||||
buffer.push_str(content.trim_end());
|
||||
buffer.push_str("\n\n");
|
||||
}
|
||||
|
||||
Ok(buffer)
|
||||
@@ -318,13 +333,18 @@ 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
|
||||
// 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())?;
|
||||
f.write_all("[]".as_bytes())?;
|
||||
Default::default()
|
||||
} else {
|
||||
let channel_json = read_to_string(&releases_file)?;
|
||||
@@ -384,14 +404,16 @@ impl ChannelReleaseStore {
|
||||
})?;
|
||||
|
||||
if !entry.metadata()?.is_file() || !fname.ends_with(".md") {
|
||||
eprintln!(
|
||||
"{}",
|
||||
format!(
|
||||
"Unexpected item in changelog entries dir: {}",
|
||||
entry.path().display()
|
||||
)
|
||||
.yellow()
|
||||
);
|
||||
if fname != ".gitkeep" {
|
||||
eprintln!(
|
||||
"{}",
|
||||
format!(
|
||||
"Unexpected item in changelog entries dir: {}",
|
||||
entry.path().display()
|
||||
)
|
||||
.yellow()
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -404,7 +426,7 @@ impl ChannelReleaseStore {
|
||||
.flatten()
|
||||
.any(|entryname| entryname == basename)
|
||||
{
|
||||
found.push(fname);
|
||||
found.push(basename.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user