summaryrefslogtreecommitdiff
path: root/docs/src/contribs.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2023-04-20 14:23:26 +0200
committerLaurenz <laurmaedje@gmail.com>2023-04-20 14:23:36 +0200
commitc117e2dc276d19b022abccac0d252bd7fc1cd44e (patch)
tree10884ac2ecd4d01053b2d38856c395e2e115775c /docs/src/contribs.rs
parent2a682f0008b91e7c33c6e65b3ecfc690268ab405 (diff)
List contributors in changelog
Co-Authored-By: Martin Haug <mhaug@live.de>
Diffstat (limited to 'docs/src/contribs.rs')
-rw-r--r--docs/src/contribs.rs97
1 files changed, 97 insertions, 0 deletions
diff --git a/docs/src/contribs.rs b/docs/src/contribs.rs
new file mode 100644
index 00000000..df1d4944
--- /dev/null
+++ b/docs/src/contribs.rs
@@ -0,0 +1,97 @@
+use std::cmp::Reverse;
+use std::collections::HashMap;
+use std::fmt::Write;
+
+use serde::Deserialize;
+
+use super::Html;
+
+/// Build HTML detailing the contributors between two tags.
+pub fn contributors(from: &str, to: &str) -> Option<Html> {
+ let staff = ["laurmaedje", "reknih"];
+
+ let url = format!("https://api.github.com/repos/typst/typst/compare/{from}...{to}");
+ let response: Response = ureq::get(&url)
+ .set("X-GitHub-Api-Version", "2022-11-28")
+ .call()
+ .ok()?
+ .into_json()
+ .ok()?;
+
+ // Determine number of contributions per person.
+ let mut contributors = HashMap::<String, Contributor>::new();
+ for commit in response.commits {
+ contributors
+ .entry(commit.author.login.clone())
+ .or_insert_with(|| Contributor {
+ login: commit.author.login,
+ avatar: commit.author.avatar_url,
+ contributions: 0,
+ })
+ .contributions += 1;
+ }
+
+ // Keep only non-staff people.
+ let mut contributors: Vec<_> = contributors
+ .into_values()
+ .filter(|c| !staff.contains(&c.login.as_str()))
+ .collect();
+
+ // Sort by highest number of commits.
+ contributors.sort_by_key(|c| Reverse(c.contributions));
+ if contributors.is_empty() {
+ return None;
+ }
+
+ let mut html = "Thanks to everyone who contributed to this release!".to_string();
+ html += "<ul class=\"contribs\">";
+
+ for Contributor { login, avatar, contributions } in contributors {
+ let login = login.replace('\"', "&quot;").replace('&', "&amp;");
+ let avatar = avatar.replace("?v=", "?s=64&v=");
+ let s = if contributions > 1 { "s" } else { "" };
+ write!(
+ html,
+ r#"<li>
+ <a href="https://github.com/{login}" target="_blank">
+ <img
+ width="64"
+ height="64"
+ src="{avatar}"
+ alt="GitHub avatar of {login}"
+ title="@{login} made {contributions} contribution{s}"
+ crossorigin="anonymous"
+ >
+ </a>
+ </li>"#
+ )
+ .unwrap();
+ }
+
+ html += "</ul>";
+
+ Some(Html::new(html))
+}
+
+#[derive(Debug)]
+struct Contributor {
+ login: String,
+ avatar: String,
+ contributions: usize,
+}
+
+#[derive(Debug, Deserialize)]
+struct Response {
+ commits: Vec<Commit>,
+}
+
+#[derive(Debug, Deserialize)]
+struct Commit {
+ author: Author,
+}
+
+#[derive(Debug, Deserialize)]
+struct Author {
+ login: String,
+ avatar_url: String,
+}