History

Add details behind a fold, but… (#198)

…parsing really needs a headline and it's probably ok to provide it. Otherwise parsing would be more complicated and it shouldn't be that way now.

Sebastian Thiel committed 5 years ago

Commit 3360b2e1 parent 634267c8 files · +171 −6Browse files

Unified · Split

8 files
  1. cargo-smart-release/src/changelog/merge.rs +3 −0
  2. cargo-smart-release/src/changelog/mod.rs +10 −4
  3. cargo-smart-release/src/changelog/parse.rs +9 −0
  4. cargo-smart-release/src/changelog/section.rs +40 −2
  5. cargo-smart-release/src/changelog/write.rs +18 −0
  6. cargo-smart-release/tests/changelog/write_and_parse/mod.rs +30 −0
  7. cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap +14 −0
  8. cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap.new +47 −0
cargo-smart-release/src/changelog/merge.rs+3−0
@@ -85,6 +85,9 @@ fn merge_section(dest: &mut Section, src: Section) { · 84 unmodified lines
85 stats @ section::Segment::Statistics(_) => {85 stats @ section::Segment::Statistics(_) => {
86 replace_all_or_append(lhs_segments, |s| matches!(s, section::Segment::Statistics(_)), stats)86 replace_all_or_append(lhs_segments, |s| matches!(s, section::Segment::Statistics(_)), stats)
87 }87 }
88 details @ section::Segment::Details(_) => {
89 replace_all_or_append(lhs_segments, |s| matches!(s, section::Segment::Details(_)), details)
90 }
88 }91 }
89 }92 }
90 *lhs_date = rhs_date;93 *lhs_date = rhs_date;
cargo-smart-release/src/changelog/mod.rs+10−4
@@ -50,10 +50,16 @@ impl Section { · 49 unmodified lines
50 pub fn is_essential(&self) -> bool {50 pub fn is_essential(&self) -> bool {
51 match self {51 match self {
52 Section::Verbatim { .. } => true,52 Section::Verbatim { .. } => true,
53 Section::Release { segments, .. } => segments.iter().any(|s| match s {53 Section::Release { segments, .. } => segments.iter().any(|s| !s.is_read_only()),
54 section::Segment::User { .. } => true,54 }
55 section::Segment::Clippy(_) | section::Segment::Statistics(_) => false,55 }
56 }),56}
57
58impl section::Segment {
59 pub fn is_read_only(&self) -> bool {
60 match self {
61 section::Segment::User { .. } => false,
62 section::Segment::Clippy(_) | section::Segment::Statistics(_) | section::Segment::Details(_) => true,
57 }63 }
58 }64 }
59}65}
cargo-smart-release/src/changelog/parse.rs+9−0
@@ -88,6 +88,15 @@ impl Section { · 87 unmodified lines
88 track_unknown_event(event, &mut unknown);88 track_unknown_event(event, &mut unknown);
89 }89 }
90 }90 }
91 Event::Html(text) if text.starts_with(section::Details::PREFIX) => {
92 record_unknown_range(&mut segments, unknown_range.take(), &body);
93 events
94 .by_ref()
95 .take_while(
96 |(e, _range)| !matches!(e, Event::Html(text) if text.starts_with(section::Details::END)),
97 )
98 .count();
99 }
91 Event::Start(Tag::Heading(indent)) => {100 Event::Start(Tag::Heading(indent)) => {
92 record_unknown_range(&mut segments, unknown_range.take(), &body);101 record_unknown_range(&mut segments, unknown_range.take(), &body);
93 enum State {102 enum State {
cargo-smart-release/src/changelog/section.rs+40−2
@@ -1,12 +1,14 @@
1use std::collections::BTreeMap;
2
1#[derive(Eq, PartialEq, Debug, Clone)]3#[derive(Eq, PartialEq, Debug, Clone)]
2pub enum Segment {4pub enum Segment {
3 /// A portion of a Section that we couldn't make sense of, but which should be kept as is nonetheless.5 /// A portion of a Section that we couldn't make sense of, but which should be kept as is nonetheless.
4 User {6 User {
5 text: String,7 text: String,
6 },8 },
7 /// A thanks clippy headline with the amount of times clippy helped9 Details(Data<Details>),
8 Clippy(Data<ThanksClippy>),
9 Statistics(Data<CommitStatistics>),10 Statistics(Data<CommitStatistics>),
11 Clippy(Data<ThanksClippy>),
10}12}
11 13
12#[derive(Eq, Debug, Clone)]14#[derive(Eq, Debug, Clone)]
@@ -24,6 +26,42 @@ impl<T: PartialEq<T>> PartialEq<Data<T>> for Data<T> { · 11 unmodified lines
24 }26 }
25}27}
26 28
29pub mod details {
30 use std::fmt;
31
32 #[derive(PartialEq, Eq, Ord, PartialOrd, Debug, Clone)]
33 pub enum Category {
34 Issue(String),
35 Uncategorized,
36 }
37
38 impl fmt::Display for Category {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Category::Uncategorized => f.write_str("Uncategorized"),
42 Category::Issue(issue) => write!(f, "#{}", issue),
43 }
44 }
45 }
46
47 #[derive(PartialEq, Eq, Debug, Clone)]
48 pub struct Message {
49 pub title: String,
50 pub body: Option<String>,
51 }
52}
53
54#[derive(PartialEq, Eq, Debug, Clone)]
55pub struct Details {
56 pub commits_by_category: BTreeMap<details::Category, Vec<details::Message>>,
57}
58
59impl Details {
60 pub const TITLE: &'static str = "Commit Details";
61 pub const PREFIX: &'static str = "<details><summary>view details</summary>";
62 pub const END: &'static str = "</details>";
63}
64
27#[derive(PartialEq, Eq, Debug, Clone)]65#[derive(PartialEq, Eq, Debug, Clone)]
28pub struct CommitStatistics {66pub struct CommitStatistics {
29 /// Amount of commits that contributed to the release67 /// Amount of commits that contributed to the release
cargo-smart-release/src/changelog/write.rs+18−0
@@ -71,6 +71,23 @@ impl section::Segment { · 70 unmodified lines
71 pub fn write_to(&self, section_level: usize, mut out: impl std::io::Write) -> std::io::Result<()> {71 pub fn write_to(&self, section_level: usize, mut out: impl std::io::Write) -> std::io::Result<()> {
72 match self {72 match self {
73 section::Segment::User { text } => out.write_all(text.as_bytes())?,73 section::Segment::User { text } => out.write_all(text.as_bytes())?,
74 section::Segment::Details(section::Data::Generated(section::Details { commits_by_category }))
75 if !commits_by_category.is_empty() =>
76 {
77 // writeln!(out, "{} {}\n", heading(section_level), section::Details::TITLE)?;
78 writeln!(out, "{}", Section::READONLY_TAG)?;
79 writeln!(out, "{}", section::Details::PREFIX)?;
80 for (category, messages) in commits_by_category.iter() {
81 writeln!(out, " * **{}**", category)?;
82 for message in messages {
83 writeln!(out, " - {}", message.title)?;
84 if let Some(body) = &message.body {
85 writeln!(out, "{}", body)?;
86 }
87 }
88 }
89 writeln!(out, "{}\n", section::Details::END)?;
90 }
74 section::Segment::Statistics(section::Data::Generated(section::CommitStatistics {91 section::Segment::Statistics(section::Data::Generated(section::CommitStatistics {
75 count,92 count,
76 duration,93 duration,
@@ -120,6 +137,7 @@ impl section::Segment { · 43 unmodified lines
120 }137 }
121 section::Segment::Clippy(_) => {}138 section::Segment::Clippy(_) => {}
122 section::Segment::Statistics(_) => {}139 section::Segment::Statistics(_) => {}
140 section::Segment::Details(_) => {}
123 };141 };
124 Ok(())142 Ok(())
125 }143 }
cargo-smart-release/tests/changelog/write_and_parse/mod.rs+30−0
@@ -6,6 +6,7 @@ use cargo_smart_release::{ · 5 unmodified lines
6use git_repository::bstr::ByteSlice;6use git_repository::bstr::ByteSlice;
7 7
8use crate::Result;8use crate::Result;
9use std::collections::BTreeMap;
9 10
10#[test]11#[test]
11fn all_section_types_round_trips_lossy() -> Result {12fn all_section_types_round_trips_lossy() -> Result {
@@ -37,6 +38,35 @@ fn all_section_types_round_trips_lossy() -> Result { · 25 unmodified lines
37 conventional_count: 20,38 conventional_count: 20,
38 unique_issues_count: 3,39 unique_issues_count: 3,
39 })),40 })),
41 section::Segment::Details(section::Data::Generated(section::Details {
42 commits_by_category: {
43 let mut h = BTreeMap::default();
44 h.insert(
45 section::details::Category::Uncategorized,
46 vec![section::details::Message {
47 title: "Just the title".into(),
48 body: None,
49 }, section::details::Message {
50 title: "title and body".into(),
51 body: Some("body with\nmultiple newlines\nwhich probably should be put into a single line but we don't go there for now.".into()),
52 }],
53 );
54 h.insert(
55 section::details::Category::Issue("42".into()),
56 vec![
57 section::details::Message {
58 title: "Just the title".into(),
59 body: None,
60 },
61 section::details::Message {
62 title: "another title".into(),
63 body: None,
64 },
65 ],
66 );
67 h
68 },
69 })),
40 ],70 ],
41 unknown: String::new(),71 unknown: String::new(),
42 },72 },
cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap+14−0
@@ -29,4 +29,18 @@ world · 28 unmodified lines
29 - 20 commits where understood as [conventional](https://www.conventionalcommits.org).29 - 20 commits where understood as [conventional](https://www.conventionalcommits.org).
30 - 3 unique issues were worked on30 - 3 unique issues were worked on
31 31
32<details><summary>Commit Details</summary>
33
34<csr-read-only-do-not-edit/>
35 * **#42**
36 - Just the title
37 - another title
38 * **Uncategorized**
39 - Just the title
40 - title and body
41body with
42multiple newlines
43which probably should be put into a single line but we don't go there for now.
44</details>
45
32 46
cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap.new+47−0
@@ -0,0 +1,47 @@
1---
2source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs
3expression: md
4
5---
6# Changelog
7
8my very own header
9
10## Unreleased
11
12<csr-unknown>
13hello
14world
15<csr-unknown/>
16#### v1.0.2-beta.2 (1970-01-01)
17
18* hello world
19 this
20##### Thanks Clippy
21
22<csr-read-only-do-not-edit/>
23[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic.
24
25##### Commit Statistics
26
27<csr-read-only-do-not-edit/>
28 - 100 commits contributed to the release over the course of 32 calendar days.
29 - 20 commits where understood as [conventional](https://www.conventionalcommits.org).
30 - 3 unique issues were worked on
31
32##### Commit Details
33
34<csr-read-only-do-not-edit/>
35<details><summary>view details</summary>
36 * **#42**
37 - Just the title
38 - another title
39 * **Uncategorized**
40 - Just the title
41 - title and body
42body with
43multiple newlines
44which probably should be put into a single line but we don't go there for now.
45</details>
46
47

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t