diff options
Diffstat (limited to 'src-tauri/src/github/mod.rs')
-rw-r--r-- | src-tauri/src/github/mod.rs | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/src-tauri/src/github/mod.rs b/src-tauri/src/github/mod.rs index 942f0db2..b336ab5c 100644 --- a/src-tauri/src/github/mod.rs +++ b/src-tauri/src/github/mod.rs @@ -1,2 +1,183 @@ pub mod pull_requests; pub mod release_notes; + +use app::constants::{APP_USER_AGENT, FLIGHTCORE_REPO_NAME, SECTION_ORDER}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use ts_rs::TS; + +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[ts(export)] +pub struct Tag { + name: String, +} + +/// Wrapper type needed for frontend +#[derive(Serialize, Deserialize, Debug, Clone, TS)] +#[ts(export)] +pub struct TagWrapper { + label: String, + value: Tag, +} + +#[derive(Debug, Deserialize)] +struct CommitInfo { + sha: String, + commit: Commit, +} + +#[derive(Debug, Deserialize)] +struct Commit { + message: 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> { + // Set the repository name. + + // Create a `reqwest` client with a user agent. + let client = reqwest::blocking::Client::builder() + .user_agent(APP_USER_AGENT) + .build() + .unwrap(); + + // 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: 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. + let tag_wrappers: Vec<TagWrapper> = tags + .into_iter() + .map(|tag| TagWrapper { + label: tag.name.clone(), + value: tag, + }) + .collect(); + + Ok(tag_wrappers) +} + +/// 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> { + // 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 repo = "R2NorthstarTools/FlightCore"; + + let mut full_patch_notes = "".to_string(); + + 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 + ); + + 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 + ); + + // Iterate over all commits in the diff + for commit in commits { + println!( + " * {} : {}", + commit.sha, + commit.commit.message.split('\n').next().unwrap() + ); + patch_notes.push( + commit + .commit + .message + .split('\n') + .next() + .unwrap() + .to_string(), + ); + } + + full_patch_notes += &generate_flightcore_release_notes(patch_notes); + + Ok(full_patch_notes.to_string()) +} + +/// Generate release notes in the format used for FlightCore +fn generate_flightcore_release_notes(commits: Vec<String>) -> String { + let grouped_commits = group_commits_by_type(commits); + let mut release_notes = String::new(); + + // Go over commit types and generate notes + for commit_type in SECTION_ORDER { + if let Some(commit_list) = grouped_commits.get(commit_type) { + if !commit_list.is_empty() { + let section_title = match commit_type { + "feat" => "**Features:**", + "fix" => "**Bug Fixes:**", + "docs" => "**Documentation:**", + "style" => "**Styles:**", + "refactor" => "**Code Refactoring:**", + "build" => "**Build:**", + "test" => "**Tests:**", + "chore" => "**Chores:**", + _ => "**Other:**", + }; + + release_notes.push_str(&format!("{}\n", section_title)); + + for commit_message in commit_list { + release_notes.push_str(&format!("- {}\n", commit_message)); + } + + release_notes.push('\n'); + } + } + } + + release_notes +} + +/// Group semantic commit messages by type +/// Commmit messages that are not formatted accordingly are marked as "other" +fn group_commits_by_type(commits: Vec<String>) -> HashMap<String, Vec<String>> { + let mut grouped_commits: HashMap<String, Vec<String>> = HashMap::new(); + let mut other_commits: Vec<String> = vec![]; + + for commit in commits { + let commit_parts: Vec<&str> = commit.splitn(2, ':').collect(); + if commit_parts.len() == 2 { + let commit_type = commit_parts[0].to_lowercase(); + let commit_description = commit_parts[1].trim().to_string(); + + // Check if known commit type + if SECTION_ORDER.contains(&commit_type.as_str()) { + let commit_list = grouped_commits.entry(commit_type.to_string()).or_default(); + commit_list.push(commit_description); + } else { + // otherwise add to list of "other" + other_commits.push(commit.to_string()); + } + } else { + other_commits.push(commit.to_string()); + } + } + grouped_commits.insert("other".to_string(), other_commits); + + grouped_commits +} |