Skip to content

Commit

Permalink
Implement changelog update functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
exzachlyvv committed Oct 25, 2024
1 parent 64ef8cb commit 82ea873
Showing 1 changed file with 127 additions and 5 deletions.
132 changes: 127 additions & 5 deletions crates/cli-tools/src/changelog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::io::BufRead;

use anyhow::{anyhow, bail, ensure, Context, Result};
use clap::ValueEnum;
use semver::Version;
use semver::{Prerelease, Version};
use tokio::process::Command;

use crate::cargo::metadata;
Expand Down Expand Up @@ -58,6 +58,37 @@ impl Changelog {
Self::parse(&String::from_utf8(fs::read(path).await?)?)
}

async fn write_file(&self, path: &str) -> Result<()> {
fs::write(path, self.to_string().as_bytes()).await
}

fn push_description(&mut self, severity: &Severity, content: &str) -> Result<()> {
let current_release = self.get_or_create_release_mut();
current_release.push_content(*severity, content)
}

// Gets newest (first) release. Creates a new one if newest release is not prerelease.
fn get_or_create_release_mut(&mut self) -> &mut Release {
let current_release = self.releases.first().unwrap();

// Current version is released, insert a new one.
if current_release.version.pre.is_empty() {
let mut next_version = Version::new(
current_release.version.major,
current_release.version.minor,
current_release.version.patch + 1,
);

next_version.pre = Prerelease::new("git").unwrap();

let new_release = Release::from(next_version);

self.releases.insert(0, new_release);
}

self.releases.first_mut().unwrap()
}

/// Parses and validates a changelog.
fn parse(input: &str) -> Result<Changelog> {
let mut releases: Vec<Release> = Vec::new();
Expand Down Expand Up @@ -147,6 +178,24 @@ impl Changelog {
);
Ok(())
}

async fn sync_cargo_toml(&self, path: &str) -> Result<()> {
let expected_version = &self.releases.first().unwrap().version;
let cargo_toml_path = format!("{path}/Cargo.toml");
let mut cargo_toml: toml::Table = fs::read_toml(&cargo_toml_path).await?;

cargo_toml["package"]["version"] = expected_version.to_string().into();

fs::write_toml(&cargo_toml_path, &cargo_toml).await?;

Ok(())
}

async fn sync_dependencies(&self, _path: &str) -> Result<()> {
// TODO

Ok(())
}
}

impl Display for Changelog {
Expand Down Expand Up @@ -209,6 +258,26 @@ struct Release {
contents: BTreeMap<Severity, Vec<String>>,
}

impl Release {
fn new(version: &str) -> Result<Self> {
Ok(Release { version: Version::parse(version)?, contents: BTreeMap::new() })
}

fn push_content(&mut self, severity: Severity, content: &str) -> Result<()> {
let entry = self.contents.entry(severity).or_default();

entry.push(content.to_string());

Ok(())
}
}

impl From<Version> for Release {
fn from(value: Version) -> Self {
Release { version: value, contents: BTreeMap::new() }
}
}

impl Display for Release {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "## {}\n", self.version)?;
Expand Down Expand Up @@ -260,12 +329,19 @@ pub async fn execute_ci() -> Result<()> {
}

/// Updates a changelog file and changelog files of dependencies.
pub async fn execute_change(path: &str, _severity: &Severity, _description: &str) -> Result<()> {
ensure!(fs::exists(path).await, "Crate does not exist: {path}");
pub async fn execute_change(path: &str, severity: &Severity, description: &str) -> Result<()> {
let changelog_file_path = format!("{path}/CHANGELOG.md");

ensure!(fs::exists(&changelog_file_path).await, "Crate does not exist: {changelog_file_path}");

let mut changelog = Changelog::read_file(&changelog_file_path).await?;

let _changelog = Changelog::read_file(&format!("{path}/CHANGELOG.md")).await?;
changelog.push_description(severity, description)?;
changelog.write_file(&changelog_file_path).await?;
changelog.sync_cargo_toml(path).await?;
changelog.sync_dependencies(path).await?;

todo!("Implement changelog updates");
Ok(())
}

#[cfg(test)]
Expand Down Expand Up @@ -717,4 +793,50 @@ mod tests {
"Unexpected prerelease line 9"
);
}

#[test]
fn get_or_create_release_mut_uses_first_when_prerelease() {
let changelog_str = r"# Changelog
## 0.6.0-git
### Major
- A change
## 0.1.0
<!-- Increment to skip CHANGELOG.md test: 0 -->
";

let mut changelog = Changelog::parse(&changelog_str).expect("Failed to parse changelog.");

let current_release = changelog.get_or_create_release_mut();

assert_eq!(current_release.version, Version::parse("0.6.0-git").unwrap());
}

#[test]
fn get_or_create_release_mut_creates_new_when_current_is_released() {
let changelog_str = r"# Changelog
## 0.6.0
### Major
- A change
## 0.1.0
<!-- Increment to skip CHANGELOG.md test: 0 -->
";

let mut changelog = Changelog::parse(&changelog_str).expect("Failed to parse changelog.");

let current_release = changelog.get_or_create_release_mut();

assert_eq!(current_release.version, Version::parse("0.6.1-git").unwrap());
// Assert the new release already inserted
assert_eq!(changelog.releases.len(), 3);
}
}

0 comments on commit 82ea873

Please sign in to comment.