mirror of https://github.com/smithy-lang/smithy-rs
Add option to create a release manifest to changelog tool (#1384)
This commit is contained in:
parent
fb5e235446
commit
83af60855f
|
@ -137,6 +137,12 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -255,6 +261,12 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "sdk-lints"
|
||||
version = "0.1.0"
|
||||
|
@ -266,6 +278,7 @@ dependencies = [
|
|||
"ordinal",
|
||||
"pretty_assertions",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"time",
|
||||
"toml",
|
||||
]
|
||||
|
@ -290,6 +303,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.81"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
|
|
@ -16,6 +16,7 @@ cargo_toml = "0.10.1"
|
|||
clap = { version = "3.1.7", features = ["derive"]}
|
||||
toml = "0.5.8"
|
||||
serde = { version = "1", features = ["derive"]}
|
||||
serde_json = "1"
|
||||
lazy_static = "1.4.0"
|
||||
time = { version = "0.3.9", features = ["local-offset"]}
|
||||
ordinal = "0.3.2"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
use crate::lint::LintError;
|
||||
use crate::{repo_root, Check, Lint};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use serde::{de, Deserialize, Deserializer};
|
||||
use serde::{de, Deserialize, Deserializer, Serialize};
|
||||
use std::fmt::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
@ -282,12 +282,28 @@ fn no_uncommited_changes(path: &Path) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub struct ReleaseMetadata {
|
||||
pub title: String,
|
||||
pub tag: String,
|
||||
pub manifest_name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ReleaseManifest {
|
||||
#[serde(rename = "tagName")]
|
||||
tag_name: String,
|
||||
name: String,
|
||||
body: String,
|
||||
prerelease: bool,
|
||||
}
|
||||
|
||||
pub(crate) fn update_changelogs(
|
||||
changelog_next: impl AsRef<Path>,
|
||||
smithy_rs_path: impl AsRef<Path>,
|
||||
aws_sdk_rust_path: impl AsRef<Path>,
|
||||
smithy_rs_release_header: &str,
|
||||
aws_sdk_rust_release_header: &str,
|
||||
smithy_rs_metadata: &ReleaseMetadata,
|
||||
aws_sdk_rust_metadata: &ReleaseMetadata,
|
||||
release_manifest_output_path: Option<&Path>,
|
||||
) -> Result<()> {
|
||||
no_uncommited_changes(changelog_next.as_ref()).context(
|
||||
"CHANGELOG.next.toml had unstaged changes. Refusing to perform changelog update.",
|
||||
|
@ -302,19 +318,35 @@ pub(crate) fn update_changelogs(
|
|||
smithy_rs,
|
||||
aws_sdk_rust,
|
||||
} = changelog.into_entries();
|
||||
for (entries, path, release_header) in [
|
||||
(smithy_rs, smithy_rs_path.as_ref(), smithy_rs_release_header),
|
||||
for (entries, path, release_metadata) in [
|
||||
(smithy_rs, smithy_rs_path.as_ref(), smithy_rs_metadata),
|
||||
(
|
||||
aws_sdk_rust,
|
||||
aws_sdk_rust_path.as_ref(),
|
||||
aws_sdk_rust_release_header,
|
||||
aws_sdk_rust_metadata,
|
||||
),
|
||||
] {
|
||||
no_uncommited_changes(path)
|
||||
.with_context(|| format!("{} had unstaged changes", path.display()))?;
|
||||
let (release_header, release_notes) = render(&entries, &release_metadata.title);
|
||||
if let Some(output_path) = release_manifest_output_path {
|
||||
let release_manifest = ReleaseManifest {
|
||||
tag_name: release_metadata.tag.clone(),
|
||||
name: release_metadata.title.clone(),
|
||||
body: release_notes.clone(),
|
||||
// All releases are pre-releases for now
|
||||
prerelease: true,
|
||||
};
|
||||
std::fs::write(
|
||||
output_path.join(&release_metadata.manifest_name),
|
||||
serde_json::to_string_pretty(&release_manifest)?,
|
||||
)?;
|
||||
}
|
||||
|
||||
let mut update = USE_UPDATE_CHANGELOGS.to_string();
|
||||
update.push('\n');
|
||||
update.push_str(&render(&entries, release_header));
|
||||
update.push_str(&release_header);
|
||||
update.push_str(&release_notes);
|
||||
let current = std::fs::read_to_string(path)?.replace(USE_UPDATE_CHANGELOGS, "");
|
||||
update.push_str(¤t);
|
||||
std::fs::write(path, update)?;
|
||||
|
@ -370,16 +402,18 @@ fn render_sdk_model_entries<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a list of changelog entries into markdown
|
||||
fn render(entries: &[ChangelogEntry], release_header: &str) -> String {
|
||||
let mut out = String::new();
|
||||
out.push_str(release_header);
|
||||
out.push('\n');
|
||||
/// Convert a list of changelog entries into markdown.
|
||||
/// Returns (header, body)
|
||||
fn render(entries: &[ChangelogEntry], release_header: &str) -> (String, String) {
|
||||
let mut header = String::new();
|
||||
header.push_str(release_header);
|
||||
header.push('\n');
|
||||
for _ in 0..release_header.len() {
|
||||
out.push('=');
|
||||
header.push('=');
|
||||
}
|
||||
out.push('\n');
|
||||
header.push('\n');
|
||||
|
||||
let mut out = String::new();
|
||||
render_handauthored(
|
||||
entries.iter().filter_map(ChangelogEntry::hand_authored),
|
||||
&mut out,
|
||||
|
@ -429,7 +463,7 @@ fn render(entries: &[ChangelogEntry], release_header: &str) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
out
|
||||
(header, out)
|
||||
}
|
||||
|
||||
pub(crate) struct ChangelogNext;
|
||||
|
@ -475,8 +509,14 @@ fn check_changelog_next(path: impl AsRef<Path>) -> std::result::Result<Changelog
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::ChangelogEntry;
|
||||
use crate::changelog::{render, Changelog, ChangelogEntries};
|
||||
|
||||
fn render_full(entries: &[ChangelogEntry], release_header: &str) -> String {
|
||||
let (header, body) = render(entries, release_header);
|
||||
return format!("{}{}", header, body);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn end_to_end_changelog() {
|
||||
let changelog_toml = r#"
|
||||
|
@ -544,7 +584,7 @@ message = "Some API change"
|
|||
smithy_rs,
|
||||
} = changelog.into_entries();
|
||||
|
||||
let smithy_rs_rendered = render(&smithy_rs, "v0.3.0 (January 4th, 2022)");
|
||||
let smithy_rs_rendered = render_full(&smithy_rs, "v0.3.0 (January 4th, 2022)");
|
||||
let smithy_rs_expected = r#"
|
||||
v0.3.0 (January 4th, 2022)
|
||||
==========================
|
||||
|
@ -567,7 +607,7 @@ Thank you for your contributions! ❤
|
|||
.trim_start();
|
||||
pretty_assertions::assert_str_eq!(smithy_rs_expected, smithy_rs_rendered);
|
||||
|
||||
let aws_sdk_rust_rendered = render(&aws_sdk_rust, "v0.1.0 (January 4th, 2022)");
|
||||
let aws_sdk_rust_rendered = render_full(&aws_sdk_rust, "v0.1.0 (January 4th, 2022)");
|
||||
let aws_sdk_expected = r#"
|
||||
v0.1.0 (January 4th, 2022)
|
||||
==========================
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::lint_cargo_toml::{CrateAuthor, CrateLicense, DocsRs};
|
|||
use crate::readmes::{ReadmesExist, ReadmesHaveFooters};
|
||||
use crate::todos::TodosHaveContext;
|
||||
use anyhow::{bail, Context, Result};
|
||||
use changelog::ReleaseMetadata;
|
||||
use clap::Parser;
|
||||
use lazy_static::lazy_static;
|
||||
use ordinal::Ordinal;
|
||||
|
@ -68,6 +69,9 @@ enum Args {
|
|||
/// Whether or not independent crate versions are being used (defaults to false)
|
||||
#[clap(long)]
|
||||
independent_versioning: bool,
|
||||
/// Optional path to output a release manifest file to
|
||||
#[clap(long)]
|
||||
release_manifest_output_path: Option<PathBuf>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -166,27 +170,44 @@ fn main() -> Result<()> {
|
|||
}
|
||||
Args::UpdateChangelog {
|
||||
independent_versioning,
|
||||
release_manifest_output_path,
|
||||
} => {
|
||||
let now = OffsetDateTime::now_local()?;
|
||||
let changelog_next_path = repo_root().join("CHANGELOG.next.toml");
|
||||
let changelog_path = repo_root().join("CHANGELOG.md");
|
||||
let aws_changelog_path = repo_root().join("aws/SDK_CHANGELOG.md");
|
||||
if independent_versioning {
|
||||
let header = date_header()?;
|
||||
let smithy_rs_metadata =
|
||||
date_based_release_metadata(now, "smithy-rs-release-manifest.json");
|
||||
let sdk_metadata =
|
||||
date_based_release_metadata(now, "aws-sdk-rust-release-manifest.json");
|
||||
changelog::update_changelogs(
|
||||
changelog_next_path,
|
||||
changelog_path,
|
||||
aws_changelog_path,
|
||||
&header,
|
||||
&header,
|
||||
&smithy_rs_metadata,
|
||||
&sdk_metadata,
|
||||
release_manifest_output_path.as_deref(),
|
||||
)?
|
||||
} else {
|
||||
let auto = auto_changelog_meta()?;
|
||||
let smithy_rs_metadata = version_based_release_metadata(
|
||||
now,
|
||||
&auto.smithy_version,
|
||||
"smithy-rs-release-manifest.json",
|
||||
);
|
||||
let sdk_metadata = version_based_release_metadata(
|
||||
now,
|
||||
&auto.sdk_version,
|
||||
"aws-sdk-rust-release-manifest.json",
|
||||
);
|
||||
changelog::update_changelogs(
|
||||
changelog_next_path,
|
||||
changelog_path,
|
||||
aws_changelog_path,
|
||||
&release_header_sync_versioned(&auto.smithy_version)?,
|
||||
&release_header_sync_versioned(&auto.sdk_version)?,
|
||||
&smithy_rs_metadata,
|
||||
&sdk_metadata,
|
||||
release_manifest_output_path.as_deref(),
|
||||
)?
|
||||
}
|
||||
}
|
||||
|
@ -199,22 +220,45 @@ struct ChangelogMeta {
|
|||
sdk_version: String,
|
||||
}
|
||||
|
||||
fn date_header() -> Result<String> {
|
||||
let now = OffsetDateTime::now_local()?;
|
||||
Ok(format!(
|
||||
fn date_based_release_metadata(
|
||||
now: OffsetDateTime,
|
||||
manifest_name: impl Into<String>,
|
||||
) -> ReleaseMetadata {
|
||||
ReleaseMetadata {
|
||||
title: date_title(&now),
|
||||
tag: format!(
|
||||
"release-{year}-{month:02}-{day:02}",
|
||||
year = now.date().year(),
|
||||
month = u8::from(now.date().month()),
|
||||
day = now.date().day()
|
||||
),
|
||||
manifest_name: manifest_name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn version_based_release_metadata(
|
||||
now: OffsetDateTime,
|
||||
version: &str,
|
||||
manifest_name: impl Into<String>,
|
||||
) -> ReleaseMetadata {
|
||||
ReleaseMetadata {
|
||||
title: format!(
|
||||
"v{version} ({date})",
|
||||
version = version,
|
||||
date = date_title(&now)
|
||||
),
|
||||
tag: format!("v{version}", version = version),
|
||||
manifest_name: manifest_name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn date_title(now: &OffsetDateTime) -> String {
|
||||
format!(
|
||||
"{month} {day}, {year}",
|
||||
month = now.date().month(),
|
||||
day = Ordinal(now.date().day()),
|
||||
year = now.date().year()
|
||||
))
|
||||
}
|
||||
|
||||
fn release_header_sync_versioned(version: &str) -> Result<String> {
|
||||
Ok(format!(
|
||||
"v{version} ({date})",
|
||||
version = version,
|
||||
date = date_header()?
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/// Discover the new version for the changelog from gradle.properties and the date.
|
||||
|
@ -266,3 +310,27 @@ fn all_runtime_crates() -> Result<impl Iterator<Item = PathBuf>> {
|
|||
fn all_cargo_tomls() -> Result<impl Iterator<Item = PathBuf>> {
|
||||
Ok(all_runtime_crates()?.map(|pkg| pkg.join("Cargo.toml")))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{date_based_release_metadata, version_based_release_metadata};
|
||||
use time::OffsetDateTime;
|
||||
|
||||
#[test]
|
||||
fn test_date_based_release_metadata() {
|
||||
let now = OffsetDateTime::from_unix_timestamp(100_000_000).unwrap();
|
||||
let result = date_based_release_metadata(now, "some-manifest.json");
|
||||
assert_eq!("March 3rd, 1973", result.title);
|
||||
assert_eq!("release-1973-03-03", result.tag);
|
||||
assert_eq!("some-manifest.json", result.manifest_name);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version_based_release_metadata() {
|
||||
let now = OffsetDateTime::from_unix_timestamp(100_000_000).unwrap();
|
||||
let result = version_based_release_metadata(now, "0.11.0", "some-other-manifest.json");
|
||||
assert_eq!("v0.11.0 (March 3rd, 1973)", result.title);
|
||||
assert_eq!("v0.11.0", result.tag);
|
||||
assert_eq!("some-other-manifest.json", result.manifest_name);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue