diff options
-rw-r--r-- | src-tauri/bindings/Project.ts | 3 | ||||
-rw-r--r-- | src-tauri/src/constants.rs | 3 | ||||
-rw-r--r-- | src-tauri/src/github/mod.rs | 135 | ||||
-rw-r--r-- | src-vue/src/views/DeveloperView.vue | 25 |
4 files changed, 159 insertions, 7 deletions
diff --git a/src-tauri/bindings/Project.ts b/src-tauri/bindings/Project.ts new file mode 100644 index 00000000..a0f00bb8 --- /dev/null +++ b/src-tauri/bindings/Project.ts @@ -0,0 +1,3 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type Project = "FlightCore" | "Northstar";
\ No newline at end of file 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() +} diff --git a/src-vue/src/views/DeveloperView.vue b/src-vue/src/views/DeveloperView.vue index 7e11bd11..77d43afc 100644 --- a/src-vue/src/views/DeveloperView.vue +++ b/src-vue/src/views/DeveloperView.vue @@ -50,7 +50,14 @@ </el-button> <h3>Release management</h3> - + <el-select v-model="selected_project" placeholder="Select"> + <el-option + v-for="item in project" + :key="item.value" + :label="item.label" + :value="item.value" + /> + </el-select> <el-button type="primary" @click="getTags"> Get tags </el-button> @@ -93,6 +100,7 @@ import { GameInstall } from "../utils/GameInstall"; import { TagWrapper } from "../../../src-tauri/bindings/TagWrapper"; import PullRequestsSelector from "../components/PullRequestsSelector.vue"; import { showErrorNotification, showNotification } from "../utils/ui"; +import { Project } from "../../../src-tauri/bindings/Project" export default defineComponent({ name: "DeveloperView", @@ -106,6 +114,17 @@ export default defineComponent({ first_tag: { label: '', value: {name: ''} }, second_tag: { label: '', value: {name: ''} }, ns_release_tags: [] as TagWrapper[], + selected_project: "FlightCore", + project: [ + { + value: 'FlightCore', + label: 'FlightCore', + }, + { + value: 'Northstar', + label: 'Northstar', + } + ], } }, computed: { @@ -182,7 +201,7 @@ export default defineComponent({ }); }, async getTags() { - await invoke<TagWrapper[]>("get_list_of_tags") + await invoke<TagWrapper[]>("get_list_of_tags", {project: this.selected_project}) .then((message) => { this.ns_release_tags = message; showNotification("Done", "Fetched tags"); @@ -192,7 +211,7 @@ export default defineComponent({ }); }, async compareTags() { - await invoke<string>("compare_tags", {firstTag: this.firstTag.value, secondTag: this.secondTag.value}) + await invoke<string>("compare_tags", {project: this.selected_project, firstTag: this.firstTag.value, secondTag: this.secondTag.value}) .then((message) => { this.release_notes_text = message; showNotification("Done", "Generated release notes"); |