@@ -4,18 +4,50 @@ use crate::{
44} ;
55use clap:: { command, crate_version, ArgMatches , Command } ;
66use colorful:: Colorful ;
7+ use reqwest:: blocking:: Client ;
8+ use serde_json:: Value ;
79use std:: {
810 env:: { current_dir, current_exe} ,
911 path:: PathBuf ,
1012 process:: exit,
13+ sync:: OnceLock ,
14+ time:: Duration ,
1115} ;
1216
1317pub type App = Command ;
1418
15- // This should 100% pull from a GCP storage bucket or something that gets updataed in CI when we trigger releases
16- // TODO: eventually, we should use this to tell the user that they need to update their CLI version
17- // (we could detect this by comparing this value with the crate_version!() macro value)
18- pub const RAPID_LATEST_VERSION : & str = "v0.4.3" ;
19+ // Fetch the latest version from GitHub API
20+ static LATEST_VERSION : OnceLock < String > = OnceLock :: new ( ) ;
21+
22+ /// Fetches the latest version from GitHub API
23+ /// Falls back to a default version if the API request fails
24+ fn fetch_latest_version ( ) -> String {
25+ let client = Client :: new ( ) ;
26+
27+ // Try to fetch from GitHub API
28+ let result = client
29+ . get ( "https://api.github.com/repos/DarrenBaldwin07/rapid/releases/latest" )
30+ . timeout ( Duration :: from_secs ( 2 ) )
31+ . header ( "User-Agent" , format ! ( "rapid-cli/{}" , crate_version!( ) ) )
32+ . send ( )
33+ . and_then ( |res| res. json :: < Value > ( ) )
34+ . ok ( ) ;
35+
36+ if let Some ( json) = result {
37+ if let Some ( tag_name) = json[ "tag_name" ] . as_str ( ) {
38+ return tag_name. to_string ( ) ;
39+ }
40+ }
41+
42+ // Fall back to hardcoded version if API call fails
43+ "v0.6.0" . to_string ( )
44+ }
45+
46+ /// Get the latest Rapid version
47+ /// Uses a static OnceLock to ensure we only fetch it once per CLI execution
48+ pub fn rapid_latest_version ( ) -> & ' static str {
49+ LATEST_VERSION . get_or_init ( fetch_latest_version) . as_str ( )
50+ }
1951
2052/// Returns what the current working directory of the user is
2153pub fn current_directory ( ) -> PathBuf {
@@ -92,9 +124,34 @@ impl RapidCLI {
92124 exit ( 64 ) ;
93125 }
94126
127+ // Check if there's a newer version available
128+ self . check_for_updates ( ) ;
129+
95130 // This outputs only when a command succeeds (would be cool to capture analytics here at some point)
96131 Ok ( ( ) )
97132 }
133+
134+ fn check_for_updates ( & self ) {
135+ let current_version = crate_version ! ( ) ;
136+ let latest_version = rapid_latest_version ( ) ;
137+
138+ // Remove 'v' prefix from latest_version for comparison if it exists
139+ let latest_version_str = if latest_version. starts_with ( 'v' ) {
140+ & latest_version[ 1 ..]
141+ } else {
142+ latest_version
143+ } ;
144+
145+ if latest_version_str != current_version {
146+ println ! (
147+ "\n {} A new version of Rapid is available: {} (you have {})" ,
148+ "⚠️" . yellow( ) ,
149+ latest_version. green( ) . bold( ) ,
150+ current_version. yellow( )
151+ ) ;
152+ println ! ( " Run 'cargo install rapid-cli@{}' to update" , latest_version_str) ;
153+ }
154+ }
98155}
99156
100157// TODO: update this to actually be a legit health template
0 commit comments