diff --git a/.gitignore b/.gitignore index 546701f..4f0b8af 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /book/book /book/src/SUMMARY.md /book/src/bittorrent.md +/book/src/changelog.md /book/src/commands.md /book/src/commands/ /book/src/faq.md diff --git a/bin/gen/src/changelog.rs b/bin/gen/src/changelog.rs index 31ac17e..1c9821c 100644 --- a/bin/gen/src/changelog.rs +++ b/bin/gen/src/changelog.rs @@ -99,18 +99,22 @@ impl Changelog { Self { releases } } -} -impl Display for Changelog { - #[throws(fmt::Error)] - fn fmt(&self, f: &mut Formatter) { - writeln!(f, "Changelog")?; - writeln!(f, "=========")?; + #[throws] + pub(crate) fn render(&self, book: bool) -> String { + let mut lines: Vec = Vec::new(); + + lines.push("Changelog".into()); + lines.push("=========".into()); for release in &self.releases { - writeln!(f)?; - writeln!(f)?; - write!(f, "{}", release)?; + lines.push("".into()); + lines.push("".into()); + release.render(&mut lines, book)?; } + + let mut text = lines.join("\n"); + text.push('\n'); + text } } diff --git a/bin/gen/src/entry.rs b/bin/gen/src/entry.rs index c57b961..bab1458 100644 --- a/bin/gen/src/entry.rs +++ b/bin/gen/src/entry.rs @@ -43,48 +43,47 @@ impl Entry { } } - fn permanent_shorthash(&self) -> String { - if self.head { - "x".repeat(12) - } else { - self.hash[..12].into() - } + fn shorthash(&self) -> String { + self.hash[..12].into() } -} -impl Display for Entry { - #[throws(fmt::Error)] - fn fmt(&self, f: &mut Formatter) { + #[throws] + pub(crate) fn render(&self, lines: &mut Vec, book: bool) { + let mut line = "- ".to_string(); + let url = self.url(); - let shorthash = self.permanent_shorthash(); - - write!( - f, + line.push_str(&format!( "{} [`{}`]({}) {}", - self.metadata.kind.emoji(), - shorthash, + if book { + self.metadata.kind.emoji_character() + } else { + self.metadata.kind.emoji_name() + }, + self.shorthash(), url, self.summary - )?; + )); if let Some(pr) = &self.metadata.pr { let n = pr.path_segments().unwrap().last().unwrap(); - write!(f, " ([#{}]({}))", n, pr)?; + line.push_str(&format!(" ([#{}]({}))", n, pr)); } if !self.metadata.fixes.is_empty() { - write!(f, " - Fixes ")?; + line.push_str(" - Fixes "); for (i, issue) in self.metadata.fixes.iter().enumerate() { if i > 0 { - write!(f, ", ")?; + line.push_str(", "); } let n = issue.path_segments().unwrap().last().unwrap(); - write!(f, "[#{}]({})", n, issue)?; + line.push_str(&format!("[#{}]({})", n, issue)); } } - write!(f, " - _{}_", self.author)?; + line.push_str(&format!(" - _{}_", self.author)); + + lines.push(line); } } diff --git a/bin/gen/src/kind.rs b/bin/gen/src/kind.rs index f299fc2..e838e08 100644 --- a/bin/gen/src/kind.rs +++ b/bin/gen/src/kind.rs @@ -30,7 +30,23 @@ pub(crate) enum Kind { } impl Kind { - pub(crate) fn emoji(self) -> &'static str { + pub(crate) fn emoji_character(self) -> &'static str { + match self { + Self::Added => "✨", + Self::Breaking => "💥", + Self::Changed => "⚡️", + Self::Dependencies => "⬆️", + Self::Development => "🔧", + Self::Distribution => "📦", + Self::Documentation => "📚", + Self::Fixed => "🐛", + Self::Reform => "🎨", + Self::Release => "🔖", + Self::Testing => "✅", + } + } + + pub(crate) fn emoji_name(self) -> &'static str { match self { Self::Added => ":sparkles:", Self::Breaking => ":boom:", diff --git a/bin/gen/src/opt.rs b/bin/gen/src/opt.rs index 55426cd..9b72e24 100644 --- a/bin/gen/src/opt.rs +++ b/bin/gen/src/opt.rs @@ -93,7 +93,7 @@ impl Opt { let path = project.root.join("CHANGELOG.md"); - fs::write(&path, changelog.to_string()).context(error::Filesystem { path })?; + fs::write(&path, changelog.render(false)?).context(error::Filesystem { path })?; } #[throws] @@ -124,6 +124,7 @@ impl Opt { "/README.md", "/book/src/SUMMARY.md", "/book/src/bittorrent.md", + "/book/src/changelog.md", "/book/src/commands.md", "/book/src/commands/*", "/book/src/faq.md", @@ -182,9 +183,11 @@ impl Opt { gen(HEAD)?; - let head = project.repo.head()?.peel_to_commit()?; + let head = project.repo.head()?; - let parent = head.parent(0)?; + let head_commit = head.peel_to_commit()?; + + let parent = head_commit.parent(0)?; let parent_hash = parent.id().to_string(); @@ -192,12 +195,20 @@ impl Opt { gen(&parent_hash)?; - cmd!("diff", "-r", parent_hash, HEAD) + cmd!("colordiff", "-ur", parent_hash, HEAD) .current_dir(tmp.path()) .status_into_result() .ok(); - cmd!("git", "checkout", &head.id().to_string()).status_into_result()?; + cmd!( + "git", + "checkout", + head + .shorthand() + .map(str::to_owned) + .unwrap_or_else(|| head_commit.id().to_string()) + ) + .status_into_result()?; } #[throws] @@ -245,6 +256,11 @@ impl Opt { Summary::new(project).render_to(project.root.join("book/src/SUMMARY.md"))?; Introduction::new(&project.config).render_to(project.root.join("book/src/introduction.md"))?; + + let changelog = Changelog::new(&project)?; + + let dst = project.root.join("book/src/changelog.md"); + fs::write(&dst, changelog.render(true)?).context(error::Filesystem { path: dst })?; } #[throws] diff --git a/bin/gen/src/release.rs b/bin/gen/src/release.rs index 17192b2..570452b 100644 --- a/bin/gen/src/release.rs +++ b/bin/gen/src/release.rs @@ -6,9 +6,9 @@ pub(crate) struct Release { pub(crate) entries: Vec, } -impl Display for Release { - #[throws(fmt::Error)] - fn fmt(&self, f: &mut Formatter) { +impl Release { + #[throws] + pub(crate) fn render(&self, lines: &mut Vec, book: bool) { let time = self.time.format("%Y-%m-%d"); let header = match &self.version { @@ -19,11 +19,11 @@ impl Display for Release { None => format!("UNRELEASED - {}", time), }; - writeln!(f, "{}", header)?; - writeln!(f, "{}", "-".repeat(header.len()))?; + lines.push(header.clone()); + lines.push("-".repeat(header.len())); for entry in &self.entries { - writeln!(f, "- {}", entry)?; + entry.render(lines, book)?; } } } diff --git a/bin/gen/templates/SUMMARY.md b/bin/gen/templates/SUMMARY.md index eb9348a..da78356 100644 --- a/bin/gen/templates/SUMMARY.md +++ b/bin/gen/templates/SUMMARY.md @@ -5,6 +5,8 @@ Summary - [FAQ](./faq.md) +- [Changelog](./changelog.md) + {{commands}} - [Bittorrent](./bittorrent.md)