aboutsummaryrefslogtreecommitdiff
path: root/src-tauri/src/github/release_notes.rs
blob: 8858c3d5dc6fb02c4be1518f2e73c5a360360766 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
use serde::{Deserialize, Serialize};
use std::vec::Vec;
use ts_rs::TS;

#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct ReleaseInfo {
    pub name: String,
    pub published_at: String,
    pub body: String,
}

#[derive(Serialize, Deserialize, Debug, Clone, TS)]
#[ts(export)]
pub struct FlightCoreVersion {
    tag_name: String,
    published_at: String,
}

/// Gets newest FlighCore version from GitHub
#[tauri::command]
pub async fn get_newest_flightcore_version() -> Result<FlightCoreVersion, String> {
    // Get newest version number from GitHub API
    log::info!("Checking GitHub API");
    let octocrab = octocrab::instance();
    let page = octocrab
        .repos("R2NorthstarTools", "FlightCore")
        .releases()
        .list()
        // Optional Parameters
        .per_page(1)
        .page(1u32)
        // Send the request
        .send()
        .await
        .map_err(|err| err.to_string())?;

    // Get newest element
    let latest_release_item = &page.items[0];

    let flightcore_version = FlightCoreVersion {
        tag_name: latest_release_item.tag_name.clone(),
        published_at: latest_release_item.published_at.unwrap().to_rfc3339(),
    };
    log::info!("Done checking GitHub API");

    Ok(flightcore_version)
}

/// Checks if installed FlightCore version is up-to-date
/// false -> FlightCore install is up-to-date
/// true  -> FlightCore install is outdated
#[tauri::command]
pub async fn check_is_flightcore_outdated() -> Result<bool, String> {
    let newest_flightcore_release = get_newest_flightcore_version().await?;
    // Parse version number excluding leading `v`
    let newest_version = semver::Version::parse(&newest_flightcore_release.tag_name[1..]).unwrap();

    // Get version of installed FlightCore
    let current_version = env!("CARGO_PKG_VERSION");
    let current_version = semver::Version::parse(current_version).unwrap();

    #[cfg(debug_assertions)]
    let is_outdated = current_version < newest_version;
    #[cfg(not(debug_assertions))]
    let is_outdated = current_version != newest_version;

    // If outdated, check how new the update is
    if is_outdated {
        // Time to wait (2h)    h *  m *  s
        let threshold_seconds = 2 * 60 * 60;

        // Get current time
        let current_time = chrono::Utc::now();

        // Get latest release time from GitHub API response
        let result = chrono::DateTime::parse_from_rfc3339(&newest_flightcore_release.published_at)
            .unwrap()
            .with_timezone(&chrono::Utc);

        // Check if current time is outside of threshold
        let diff = current_time - result;
        if diff.num_seconds() < threshold_seconds {
            // User would be outdated but the newest release is recent
            // therefore we do not wanna show outdated warning.
            return Ok(false);
        }
        return Ok(true);
    }

    Ok(is_outdated)
}

#[tauri::command]
pub async fn get_northstar_release_notes() -> Result<Vec<ReleaseInfo>, String> {
    let octocrab = octocrab::instance();
    let page = octocrab
        .repos("R2Northstar", "Northstar")
        .releases()
        .list()
        // Optional Parameters
        .per_page(25)
        .page(1u32)
        // Send the request
        .send()
        .await
        .map_err(|err| err.to_string())?;

    // TODO there's probably a way to automatically serialize into the struct but I don't know yet how to
    let mut release_info_vector: Vec<ReleaseInfo> = vec![];
    for item in page.items {
        let release_info = ReleaseInfo {
            name: item.name.ok_or(String::from("Release name not found"))?,
            published_at: item
                .published_at
                .ok_or(String::from("Release date not found"))?
                .to_rfc3339(),
            body: item.body.ok_or(String::from("Release body not found"))?,
        };
        release_info_vector.push(release_info);
    }

    log::info!("Done checking GitHub API");

    Ok(release_info_vector)
}

/// Checks latest GitHub release and generates a announcement message for Discord based on it
#[tauri::command]
pub async fn generate_release_note_announcement() -> Result<String, String> {
    let octocrab = octocrab::instance();
    let page = octocrab
        .repos("R2Northstar", "Northstar")
        .releases()
        .list()
        // Optional Parameters
        .per_page(1)
        .page(1u32)
        // Send the request
        .send()
        .await
        .unwrap();

    // Get newest element
    let latest_release_item = &page.items[0];

    // Extract the URL to the GitHub release note
    let github_release_link = latest_release_item.html_url.clone();

    // Extract release version number
    let current_ns_version = &latest_release_item.tag_name;

    // Extract changelog and format it
    let changelog = remove_markdown_links::remove_markdown_links(
        latest_release_item
            .body
            .as_ref()
            .unwrap()
            .split("**Contributors:**")
            .next()
            .unwrap()
            .trim(),
    );

    // Strings to insert for different sections
    // Hardcoded for now
    let general_info = "REPLACE ME";
    let modders_info = "Mod compatibility should not be impacted";
    let server_hosters_info = "REPLACE ME";

    // Build announcement string
    let return_string = format!(
        r"Hello beautiful people <3
**Northstar `{current_ns_version}` is out!**

{general_info}

**__Modders:__**

{modders_info}

**__Server hosters:__**

{server_hosters_info}

**__Changelog:__**
```
{changelog}
```
{github_release_link}

Checkout #installation on how to install/update Northstar
(the process is the same for both, using a Northstar installer like FlightCore, Viper, or VTOL is recommended over manual installation)

If you do notice any bugs, please open an issue on Github or drop a message in the thread below
"
    );

    // Return built announcement message
    Ok(return_string.to_string())
}