-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Display for Changelog. Hooked up to parsing validation. #595
base: dev/changelog
Are you sure you want to change the base?
Changes from all commits
84517ca
e584ce0
6922aa6
a360f1e
6c717be
10d2c62
0d257ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -14,11 +14,12 @@ | |||||||||||||||||
|
||||||||||||||||||
use core::str; | ||||||||||||||||||
use std::collections::BTreeMap; | ||||||||||||||||||
use std::fmt::Write; | ||||||||||||||||||
use std::fmt::{Display, Write}; | ||||||||||||||||||
use std::io::BufRead; | ||||||||||||||||||
use std::process::Command; | ||||||||||||||||||
|
||||||||||||||||||
use anyhow::{anyhow, bail, ensure, Context, Result}; | ||||||||||||||||||
use itertools::Itertools; | ||||||||||||||||||
use semver::Version; | ||||||||||||||||||
use wasefire_cli_tools::{cmd, fs}; | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -29,6 +30,16 @@ pub enum ReleaseType { | |||||||||||||||||
Patch, | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl Display for ReleaseType { | ||||||||||||||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||||||||||||||
match self { | ||||||||||||||||||
Self::Major => write!(f, "Major"), | ||||||||||||||||||
Self::Minor => write!(f, "Minor"), | ||||||||||||||||||
Self::Patch => write!(f, "Patch"), | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[derive(Debug, Default, PartialEq, Eq)] | ||||||||||||||||||
struct Changelog { | ||||||||||||||||||
releases: Vec<Release>, | ||||||||||||||||||
|
@@ -154,7 +165,28 @@ impl Changelog { | |||||||||||||||||
); | ||||||||||||||||||
ensure!(last_release.contents.is_empty(), "The last release must contain no changes"); | ||||||||||||||||||
|
||||||||||||||||||
Ok(Changelog { releases, skip_counter }) | ||||||||||||||||||
let changelog = Changelog { releases, skip_counter }; | ||||||||||||||||||
let output_string = format!("{changelog}"); | ||||||||||||||||||
|
||||||||||||||||||
ensure!( | ||||||||||||||||||
output_string == contents, | ||||||||||||||||||
"Input string does not equal rendered changelog.\n\nIn: {contents}\n\nOut: {contents}" | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably more readable to use the |
||||||||||||||||||
); | ||||||||||||||||||
|
||||||||||||||||||
Ok(changelog) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl Display for Changelog { | ||||||||||||||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||||||||||||||
let releases_string = self.releases.iter().map(|release| format!("{release}")).join("\n\n"); | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not efficient to build a string for each version and then join them. We want to output directly to the formatter.
Suggested change
Also this permits getting rid of |
||||||||||||||||||
|
||||||||||||||||||
write!( | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same, we can split this in 2 around the for-loop above. writeln!(f, "# Changelog\n")?;
for release in &self.releases { ... }
writeln!(f, "<!-- Increment ...: {skip_counter} -->") |
||||||||||||||||||
f, | ||||||||||||||||||
"# Changelog\n\n{releases_string}\n\n<!-- Increment to skip CHANGELOG.md test: {} \ | ||||||||||||||||||
-->\n", | ||||||||||||||||||
self.skip_counter | ||||||||||||||||||
) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -171,6 +203,21 @@ impl Release { | |||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl Display for Release { | ||||||||||||||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||||||||||||||
write!(f, "## {}", self.version)?; | ||||||||||||||||||
|
||||||||||||||||||
for (release_type, descriptions) in &self.contents { | ||||||||||||||||||
let description_string = | ||||||||||||||||||
descriptions.iter().map(|description| format!("- {description}")).join("\n"); | ||||||||||||||||||
|
||||||||||||||||||
write!(f, "\n\n### {release_type}\n\n{description_string}")?; | ||||||||||||||||||
Comment on lines
+211
to
+214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here.
Suggested change
|
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
Ok(()) | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Validates all changelog files. | ||||||||||||||||||
pub fn execute_ci() -> Result<()> { | ||||||||||||||||||
let paths = cmd::output(Command::new("git").args(["ls-files", "*/CHANGELOG.md"]))?; | ||||||||||||||||||
|
@@ -239,7 +286,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Changelog::parse(changelog).expect("Failed to parse changelog."), | ||||||||||||||||||
|
@@ -289,6 +337,55 @@ mod tests { | |||||||||||||||||
); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn write_changelog_success() { | ||||||||||||||||||
let changelog = r"# Changelog | ||||||||||||||||||
|
||||||||||||||||||
## 0.3.0 | ||||||||||||||||||
|
||||||||||||||||||
### Major | ||||||||||||||||||
|
||||||||||||||||||
- major update 1 | ||||||||||||||||||
- major update 2 | ||||||||||||||||||
|
||||||||||||||||||
### Minor | ||||||||||||||||||
|
||||||||||||||||||
- minor update 1 | ||||||||||||||||||
- minor update 2 | ||||||||||||||||||
|
||||||||||||||||||
### Patch | ||||||||||||||||||
|
||||||||||||||||||
- patch update 1 | ||||||||||||||||||
- patch update 2 | ||||||||||||||||||
|
||||||||||||||||||
## 0.2.0 | ||||||||||||||||||
|
||||||||||||||||||
### Major | ||||||||||||||||||
|
||||||||||||||||||
- major update 1 | ||||||||||||||||||
- major update 2 | ||||||||||||||||||
|
||||||||||||||||||
### Minor | ||||||||||||||||||
|
||||||||||||||||||
- minor update 1 | ||||||||||||||||||
- minor update 2 | ||||||||||||||||||
|
||||||||||||||||||
### Patch | ||||||||||||||||||
|
||||||||||||||||||
- patch update 1 | ||||||||||||||||||
- patch update 2 | ||||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
format!("{}", Changelog::parse(changelog).expect("Failed to parse changelog.")), | ||||||||||||||||||
changelog | ||||||||||||||||||
); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#[test] | ||||||||||||||||||
fn parse_changelog_with_missing_release_type_success() { | ||||||||||||||||||
let changelog = r"# Changelog | ||||||||||||||||||
|
@@ -316,7 +413,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Changelog::parse(changelog).expect("Failed to parse changelog."), | ||||||||||||||||||
|
@@ -368,7 +466,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Changelog::parse(changelog).expect("Failed to parse changelog."), | ||||||||||||||||||
|
@@ -407,7 +506,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
@@ -421,7 +521,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Changelog::parse(changelog).expect("Failed to parse changelog."), | ||||||||||||||||||
|
@@ -438,9 +539,11 @@ mod tests { | |||||||||||||||||
#[test] | ||||||||||||||||||
fn parse_changelog_handles_skip_counter_at_end() { | ||||||||||||||||||
let changelog = r"# Changelog | ||||||||||||||||||
|
||||||||||||||||||
## 0.1.0 | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 5 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 5 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert_eq!( | ||||||||||||||||||
Changelog::parse(changelog).expect("Failed to parse changelog."), | ||||||||||||||||||
|
@@ -492,7 +595,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
- A change | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
@@ -504,7 +608,8 @@ mod tests { | |||||||||||||||||
fn parse_changelog_versions_requires_at_least_one_release() { | ||||||||||||||||||
let changelog = r"# Changelog | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
@@ -522,7 +627,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
- A change | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
@@ -540,7 +646,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
- A change | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
@@ -564,7 +671,8 @@ mod tests { | |||||||||||||||||
|
||||||||||||||||||
- A change | ||||||||||||||||||
|
||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 -->"; | ||||||||||||||||||
<!-- Increment to skip CHANGELOG.md test: 0 --> | ||||||||||||||||||
"; | ||||||||||||||||||
|
||||||||||||||||||
assert!(Changelog::parse(changelog) | ||||||||||||||||||
.expect_err("Parse changelog was successful.") | ||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated but I think it's worth doing it soon, is to rename
ReleaseType
toScope
to be a bit more abstract, because this type is used for 2 things:And the second thing is actually only a consequence of the first, so the name should be more relevant to the first, which is describing the scope/impact of a change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we could also use the name
Severity
since it's used here.