Unnamed repository; edit this file 'description' to name the repository.
Implement `xtask publish-release-notes` to publish release notes on GitHub Releases
Noritada Kobayashi 2022-12-11
parent 0eb537f · commit f06a29f
-rw-r--r--xtask/src/flags.rs15
-rw-r--r--xtask/src/main.rs2
-rw-r--r--xtask/src/publish.rs80
3 files changed, 97 insertions, 0 deletions
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 0fce488983..2100479701 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -34,6 +34,13 @@ xflags::xflags! {
cmd dist {
optional --client-patch-version version: String
}
+ /// Read a changelog AsciiDoc file and update the GitHub Releases entry in Markdown.
+ cmd publish-release-notes {
+ /// Only run conversion and show the result.
+ optional --dry-run
+ /// Target changelog file.
+ required changelog: String
+ }
cmd metrics {
optional --dry-run
}
@@ -59,6 +66,7 @@ pub enum XtaskCmd {
Release(Release),
Promote(Promote),
Dist(Dist),
+ PublishReleaseNotes(PublishReleaseNotes),
Metrics(Metrics),
Bb(Bb),
}
@@ -91,6 +99,13 @@ pub struct Dist {
}
#[derive(Debug)]
+pub struct PublishReleaseNotes {
+ pub changelog: String,
+
+ pub dry_run: bool,
+}
+
+#[derive(Debug)]
pub struct Metrics {
pub dry_run: bool,
}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index a37f469adc..6a45033ada 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -15,6 +15,7 @@ mod flags;
mod install;
mod release;
mod dist;
+mod publish;
mod metrics;
use anyhow::bail;
@@ -36,6 +37,7 @@ fn main() -> anyhow::Result<()> {
flags::XtaskCmd::Release(cmd) => cmd.run(sh),
flags::XtaskCmd::Promote(cmd) => cmd.run(sh),
flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
+ flags::XtaskCmd::PublishReleaseNotes(cmd) => cmd.run(sh),
flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
flags::XtaskCmd::Bb(cmd) => {
{
diff --git a/xtask/src/publish.rs b/xtask/src/publish.rs
new file mode 100644
index 0000000000..8045334207
--- /dev/null
+++ b/xtask/src/publish.rs
@@ -0,0 +1,80 @@
+mod notes;
+
+use crate::flags;
+use anyhow::{anyhow, bail, Result};
+use std::env;
+use xshell::{cmd, Shell};
+
+impl flags::PublishReleaseNotes {
+ pub(crate) fn run(self, sh: &Shell) -> Result<()> {
+ let asciidoc = sh.read_file(&self.changelog)?;
+ let markdown = notes::convert_asciidoc_to_markdown(std::io::Cursor::new(&asciidoc))?;
+ let tag_name = extract_tag_name(&self.changelog)?;
+ if self.dry_run {
+ println!("{}", markdown);
+ } else {
+ update_release(sh, &tag_name, &markdown)?;
+ }
+ Ok(())
+ }
+}
+
+fn extract_tag_name<P: AsRef<std::path::Path>>(path: P) -> Result<String> {
+ let file_name = path
+ .as_ref()
+ .file_name()
+ .ok_or_else(|| anyhow!("file name is not specified as `changelog`"))?
+ .to_string_lossy();
+
+ let mut chars = file_name.chars();
+ if file_name.len() >= 10
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap() == '-'
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap() == '-'
+ && chars.next().unwrap().is_ascii_digit()
+ && chars.next().unwrap().is_ascii_digit()
+ {
+ Ok(file_name[0..10].to_owned())
+ } else {
+ bail!("extraction of date from the file name failed")
+ }
+}
+
+fn update_release(sh: &Shell, tag_name: &str, release_notes: &str) -> Result<()> {
+ let token = match env::var("GITHUB_TOKEN") {
+ Ok(token) => token,
+ Err(_) => bail!("Please obtain a personal access token from https://github.com/settings/tokens and set the `GITHUB_TOKEN` environment variable."),
+ };
+ let accept = "Accept: application/vnd.github+json";
+ let authorization = format!("Authorization: Bearer {}", token);
+ let api_version = "X-GitHub-Api-Version: 2022-11-28";
+ let release_url = "https://api.github.com/repos/rust-lang/rust-analyzer/releases";
+
+ let release_json = cmd!(
+ sh,
+ "curl -s -H {accept} -H {authorization} -H {api_version} {release_url}/tags/{tag_name}"
+ )
+ .read()?;
+ let release_id = cmd!(sh, "jq .id").stdin(release_json).read()?;
+
+ let mut patch = String::new();
+ write_json::object(&mut patch)
+ .string("tag_name", &tag_name)
+ .string("target_commitish", "master")
+ .string("name", &tag_name)
+ .string("body", &release_notes)
+ .bool("draft", false)
+ .bool("prerelease", false);
+ let _ = cmd!(
+ sh,
+ "curl -s -X PATCH -H {accept} -H {authorization} -H {api_version} {release_url}/{release_id} -d {patch}"
+ )
+ .read()?;
+
+ Ok(())
+}