diff options
author | GeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com> | 2023-05-08 15:24:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-08 15:24:33 +0200 |
commit | 0262255b0dfb598376f1e7063cc98bfd6eace410 (patch) | |
tree | 4ca45f5fcffc4976b112f29244abd0f471417a08 /src-tauri/src | |
parent | be9b0d32dd13d66027083f0fcfa8b4e05eb2d134 (diff) | |
download | FlightCore-0262255b0dfb598376f1e7063cc98bfd6eace410.tar.gz FlightCore-0262255b0dfb598376f1e7063cc98bfd6eace410.zip |
feat: Generate Northstar release notes (#277)
* feat: Allow selecting project
to generate release notes for
* fix: Add missing TypeScript bindings
* feat: Pass project to backend on tag compare
* fix: Check for unsupported project
* feat: Allow fetching tags from Northstar repo
* fix: Formatting and fixing typo
* feat: Copy over Northstar release note generation
from previous PR
* refactor: Use Tag struct instead of string
Allows for extendability in the future
* fix: Use proper user-agent for web request
* fix: Remove debug log prints
* refactor: Use separete function for FlightCore
release note generation
One function for each FlightCore and Northstar
* feat: Make CommitAuthor optional
to deal with rebase commits that don't have a PR linked
* fix: Address clippy issues
* fix: Remove debug prints
* docs: Add comments
* refactor: Move import to top of source file
Diffstat (limited to 'src-tauri/src')
-rw-r--r-- | src-tauri/src/constants.rs | 3 | ||||
-rw-r--r-- | src-tauri/src/github/mod.rs | 135 |
2 files changed, 134 insertions, 4 deletions
diff --git a/src-tauri/src/constants.rs b/src-tauri/src/constants.rs index 8c88df1e..6e294e55 100644 --- a/src-tauri/src/constants.rs +++ b/src-tauri/src/constants.rs @@ -48,3 +48,6 @@ pub const REFRESH_DELAY: Duration = Duration::from_secs(5 * 60); // Flightcore repo name and org name on GitHub pub const FLIGHTCORE_REPO_NAME: &str = "R2NorthstarTools/FlightCore"; + +// Northstar release repo name and org name on GitHub +pub const NORTHSTAR_RELEASE_REPO_NAME: &str = "R2Northstar/Northstar"; diff --git a/src-tauri/src/github/mod.rs b/src-tauri/src/github/mod.rs index b336ab5c..12729de2 100644 --- a/src-tauri/src/github/mod.rs +++ b/src-tauri/src/github/mod.rs @@ -1,7 +1,10 @@ pub mod pull_requests; pub mod release_notes; -use app::constants::{APP_USER_AGENT, FLIGHTCORE_REPO_NAME, SECTION_ORDER}; +use app::constants::{ + APP_USER_AGENT, FLIGHTCORE_REPO_NAME, NORTHSTAR_RELEASE_REPO_NAME, SECTION_ORDER, +}; +use regex::Regex; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use ts_rs::TS; @@ -12,6 +15,13 @@ pub struct Tag { name: String, } +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, TS)] +#[ts(export)] +pub enum Project { + FlightCore, + Northstar, +} + /// Wrapper type needed for frontend #[derive(Serialize, Deserialize, Debug, Clone, TS)] #[ts(export)] @@ -24,6 +34,7 @@ pub struct TagWrapper { struct CommitInfo { sha: String, commit: Commit, + author: Option<CommitAuthor>, } #[derive(Debug, Deserialize)] @@ -32,13 +43,18 @@ struct Commit { } #[derive(Debug, Deserialize)] +struct CommitAuthor { + login: String, +} + +#[derive(Debug, Deserialize)] struct Comparison { commits: Vec<CommitInfo>, } /// Get a list of tags on the FlightCore repo #[tauri::command] -pub fn get_list_of_tags() -> Result<Vec<TagWrapper>, String> { +pub fn get_list_of_tags(project: Project) -> Result<Vec<TagWrapper>, String> { // Set the repository name. // Create a `reqwest` client with a user agent. @@ -47,8 +63,14 @@ pub fn get_list_of_tags() -> Result<Vec<TagWrapper>, String> { .build() .unwrap(); + // Switch repo to fetch from based on project + let repo_name = match project { + Project::FlightCore => FLIGHTCORE_REPO_NAME, + Project::Northstar => NORTHSTAR_RELEASE_REPO_NAME, + }; + // Fetch the list of tags for the repository as a `Vec<Tag>`. - let tags_url = format!("https://api.github.com/repos/{}/tags", FLIGHTCORE_REPO_NAME); + let tags_url = format!("https://api.github.com/repos/{}/tags", repo_name); let tags: Vec<Tag> = client.get(tags_url).send().unwrap().json().unwrap(); // Map each `Tag` element to a `TagWrapper` element with the desired label and `Tag` value. @@ -65,7 +87,14 @@ pub fn get_list_of_tags() -> Result<Vec<TagWrapper>, String> { /// Use GitHub API to compare two tags of the same repo against each other and get the resulting changes #[tauri::command] -pub fn compare_tags(first_tag: Tag, second_tag: Tag) -> Result<String, String> { +pub fn compare_tags(project: Project, first_tag: Tag, second_tag: Tag) -> Result<String, String> { + match project { + Project::FlightCore => compare_tags_flightcore(first_tag, second_tag), + Project::Northstar => compare_tags_northstar(first_tag, second_tag), + } +} + +pub fn compare_tags_flightcore(first_tag: Tag, second_tag: Tag) -> Result<String, String> { // Fetch the list of commits between the two tags. // Create a `reqwest` client with a user agent. @@ -181,3 +210,101 @@ fn group_commits_by_type(commits: Vec<String>) -> HashMap<String, Vec<String>> { grouped_commits } + +/// Compares two tags on Northstar repo and generates release notes over the diff in tags +/// over the 3 major repos (Northstar, NorthstarLauncher, NorthstarMods) +pub fn compare_tags_northstar(first_tag: Tag, second_tag: Tag) -> Result<String, String> { + // Fetch the list of commits between the two tags. + + // Create a `reqwest` client with a user agent. + let client = reqwest::blocking::Client::builder() + .user_agent(APP_USER_AGENT) + .build() + .unwrap(); + + let repos = [ + "R2Northstar/Northstar", + "R2Northstar/NorthstarLauncher", + "R2Northstar/NorthstarMods", + ]; + + let mut full_patch_notes = "".to_string(); + let mut authors_set = std::collections::HashSet::new(); + + for repo in repos { + full_patch_notes += &format!("{}\n\n", repo); + + let mut patch_notes: Vec<String> = [].to_vec(); + println!("{}", repo); + // let repo = "R2Northstar/NorthstarLauncher"; + let comparison_url = format!( + "https://api.github.com/repos/{}/compare/{}...{}", + repo, first_tag.name, second_tag.name + ); + + log::info!("Compare URL: {}", comparison_url.clone()); + let comparison: Comparison = client.get(&comparison_url).send().unwrap().json().unwrap(); + let commits = comparison.commits; + + // Display the list of commits. + println!( + "Commits between {} and {}:", + first_tag.name, second_tag.name + ); + + // + for commit in commits { + println!( + " * {} : {}", + commit.sha, + turn_pr_number_into_link(commit.commit.message.split('\n').next().unwrap(), repo) + ); + patch_notes.push(turn_pr_number_into_link( + commit.commit.message.split('\n').next().unwrap(), + repo, + )); + + // Store authors in set + if commit.author.is_some() { + authors_set.insert(commit.author.unwrap().login); + } + } + + full_patch_notes += &patch_notes.join("\n"); + full_patch_notes += "\n\n\n"; + } + + // Convert the set to a sorted vector. + let mut sorted_vec: Vec<String> = authors_set.into_iter().collect(); + sorted_vec.sort(); + + // Define a string to prepend to each element. + let prefix = "@"; + + // Create a new list with the prefix prepended to each element. + let prefixed_list: Vec<String> = sorted_vec.iter().map(|s| prefix.to_owned() + s).collect(); + + full_patch_notes += "**Contributors:**\n"; + full_patch_notes += &prefixed_list.join(" "); + + Ok(full_patch_notes.to_string()) +} + +/// Takes the commit title and repo slug and formats it as +/// `[commit title(SHORTENED_REPO#NUMBER)](LINK)` +fn turn_pr_number_into_link(input: &str, repo: &str) -> String { + // Extract `Mods/Launcher` from repo title + let last_line = repo + .split('/') + .rev() + .next() + .unwrap() + .trim_start_matches("Northstar"); + // Extract PR number + let re = Regex::new(r"#(\d+)").unwrap(); + + // Generate pull request link + let pull_link = format!("https://github.com/{}/pull/", repo); + re.replace_all(input, format!("[{}#$1]({}$1)", last_line, pull_link)) + .to_string() +} |