All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m59s
All build artifacts now upload to files.command.vigilcyber.com/wraith/:
- Installer: /wraith/{ver}/Wraith_{ver}_x64-setup.exe + /wraith/latest/
- MCP bridge: /wraith/{ver}/wraith-mcp-bridge.exe + /wraith/latest/
- Update bundle: /wraith/{ver}/*.nsis.zip
- Update manifest: /wraith/update.json (Tauri updater endpoint)
- Version metadata: /wraith/{ver}/version.json + /wraith/latest/
Removed: Gitea package uploads, Gitea release creation/attachment.
Updated: tauri.conf.json updater endpoint, bridge auto-download URL,
manual update checker download URL.
CI is now: build -> sign -> upload to SeaweedFS. Done.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95 lines
2.9 KiB
Rust
95 lines
2.9 KiB
Rust
//! Version check against Gitea releases API.
|
|
|
|
use serde::Serialize;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct UpdateInfo {
|
|
pub current_version: String,
|
|
pub latest_version: String,
|
|
pub update_available: bool,
|
|
pub download_url: String,
|
|
pub release_notes: String,
|
|
}
|
|
|
|
/// Check Gitea for the latest release and compare with current version.
|
|
#[tauri::command]
|
|
pub async fn check_for_updates(app_handle: tauri::AppHandle) -> Result<UpdateInfo, String> {
|
|
// Read version from tauri.conf.json (patched by CI from git tag)
|
|
// rather than CARGO_PKG_VERSION which is always 0.1.0
|
|
let current = app_handle.config().version.clone().unwrap_or_else(|| "0.0.0".to_string());
|
|
|
|
let client = reqwest::Client::builder()
|
|
.timeout(std::time::Duration::from_secs(10))
|
|
.build()
|
|
.map_err(|e| format!("HTTP client error: {}", e))?;
|
|
|
|
let resp = client
|
|
.get("https://git.command.vigilcyber.com/api/v1/repos/vstockwell/wraith/releases?limit=1")
|
|
.header("Accept", "application/json")
|
|
.send()
|
|
.await
|
|
.map_err(|e| format!("Failed to check for updates: {}", e))?;
|
|
|
|
let releases: Vec<serde_json::Value> = resp.json().await
|
|
.map_err(|e| format!("Failed to parse releases: {}", e))?;
|
|
|
|
let latest = releases.first()
|
|
.ok_or_else(|| "No releases found".to_string())?;
|
|
|
|
let tag = latest.get("tag_name")
|
|
.and_then(|v| v.as_str())
|
|
.unwrap_or("v0.0.0")
|
|
.trim_start_matches('v')
|
|
.to_string();
|
|
|
|
let notes = latest.get("body")
|
|
.and_then(|v| v.as_str())
|
|
.unwrap_or("")
|
|
.to_string();
|
|
|
|
// Direct download from SeaweedFS
|
|
let html_url = format!("https://files.command.vigilcyber.com/wraith/{}/", tag);
|
|
|
|
let update_available = version_is_newer(&tag, ¤t);
|
|
|
|
Ok(UpdateInfo {
|
|
current_version: current,
|
|
latest_version: tag,
|
|
update_available,
|
|
download_url: html_url,
|
|
release_notes: notes,
|
|
})
|
|
}
|
|
|
|
/// Compare semver strings. Returns true if `latest` is newer than `current`.
|
|
fn version_is_newer(latest: &str, current: &str) -> bool {
|
|
let parse = |v: &str| -> Vec<u32> {
|
|
v.split('.').filter_map(|s| s.parse().ok()).collect()
|
|
};
|
|
let l = parse(latest);
|
|
let c = parse(current);
|
|
for i in 0..3 {
|
|
let lv = l.get(i).copied().unwrap_or(0);
|
|
let cv = c.get(i).copied().unwrap_or(0);
|
|
if lv > cv { return true; }
|
|
if lv < cv { return false; }
|
|
}
|
|
false
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn version_comparison() {
|
|
assert!(version_is_newer("1.5.7", "1.5.6"));
|
|
assert!(version_is_newer("1.6.0", "1.5.9"));
|
|
assert!(version_is_newer("2.0.0", "1.9.9"));
|
|
assert!(!version_is_newer("1.5.6", "1.5.6"));
|
|
assert!(!version_is_newer("1.5.5", "1.5.6"));
|
|
assert!(!version_is_newer("1.4.0", "1.5.0"));
|
|
}
|
|
}
|