Skip to content

Commit 3e35061

Browse files
committed
fix: normalize upgrade changelog URL
1 parent 7954d02 commit 3e35061

2 files changed

Lines changed: 118 additions & 0 deletions

File tree

src/cortex-cli/src/upgrade_cmd.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ fn print_line(line: &str) -> Result<bool> {
338338

339339
/// Convert GitHub URLs to raw content URLs (Issue #3651)
340340
fn convert_to_raw_url(url: &str) -> String {
341+
let normalized_url = url.replace("CortexLM/cortex-cli", "CortexLM/cortex");
342+
let url = normalized_url.as_str();
343+
341344
// Handle github.com/user/repo/blob/branch/file -> raw.githubusercontent.com/user/repo/branch/file
342345
if url.contains("github.com") && url.contains("/blob/") {
343346
return url
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use std::io::{Read, Write};
2+
use std::net::{TcpListener, TcpStream};
3+
use std::process::Command;
4+
use std::thread;
5+
6+
fn read_request(stream: &mut TcpStream) -> String {
7+
let mut buf = [0_u8; 4096];
8+
let mut request = Vec::new();
9+
10+
loop {
11+
let n = stream.read(&mut buf).expect("read request");
12+
if n == 0 {
13+
break;
14+
}
15+
request.extend_from_slice(&buf[..n]);
16+
if request.windows(4).any(|window| window == b"\r\n\r\n") {
17+
break;
18+
}
19+
}
20+
21+
String::from_utf8_lossy(&request).into_owned()
22+
}
23+
24+
fn write_response(stream: &mut TcpStream, status: &str, content_type: &str, body: &str) {
25+
write!(
26+
stream,
27+
"HTTP/1.1 {status}\r\nContent-Type: {content_type}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{body}",
28+
body.len()
29+
)
30+
.expect("write response");
31+
}
32+
33+
fn serve_once(listener: &TcpListener, base_url: &str) {
34+
let (mut stream, _) = listener.accept().expect("accept request");
35+
let request = read_request(&mut stream);
36+
let first_line = request.lines().next().unwrap_or_default();
37+
38+
if first_line.starts_with("GET /v1/releases/latest?channel=stable ") {
39+
let body = format!(
40+
r#"{{
41+
"version": "0.0.8",
42+
"channel": "stable",
43+
"released_at": "2026-05-11T00:00:00Z",
44+
"changelog_url": "{base_url}/github.com/CortexLM/cortex-cli/blob/main/CHANGELOG.md",
45+
"release_notes": "test release",
46+
"assets": {{
47+
"windows-x86_64": {{"url": "{base_url}/download/windows.zip", "sha256": "abc", "size": 1}},
48+
"linux-x86_64": {{"url": "{base_url}/download/linux.tar.gz", "sha256": "abc", "size": 1}},
49+
"darwin-aarch64": {{"url": "{base_url}/download/darwin.tar.gz", "sha256": "abc", "size": 1}}
50+
}}
51+
}}"#
52+
);
53+
write_response(&mut stream, "200 OK", "application/json", &body);
54+
return;
55+
}
56+
57+
if first_line.starts_with("GET /raw.githubusercontent.com/CortexLM/cortex/main/CHANGELOG.md ") {
58+
write_response(
59+
&mut stream,
60+
"200 OK",
61+
"text/markdown",
62+
"# Changelog\n\n- fixed changelog repo URL\n",
63+
);
64+
return;
65+
}
66+
67+
write_response(&mut stream, "404 Not Found", "text/plain", "not found");
68+
}
69+
70+
#[test]
71+
fn stale_cortex_cli_changelog_url_uses_cortex_repo() {
72+
let listener = TcpListener::bind("127.0.0.1:0").expect("bind test server");
73+
listener
74+
.set_nonblocking(false)
75+
.expect("configure test server");
76+
let base_url = format!("http://{}", listener.local_addr().expect("local addr"));
77+
let server_url = base_url.clone();
78+
79+
let server = thread::spawn(move || {
80+
serve_once(&listener, &server_url);
81+
serve_once(&listener, &server_url);
82+
});
83+
84+
let home = tempfile::tempdir().expect("temp home");
85+
let output = Command::new(env!("CARGO_BIN_EXE_Cortex"))
86+
.args([
87+
"upgrade",
88+
"--changelog",
89+
"--check",
90+
"--url",
91+
base_url.as_str(),
92+
])
93+
.env("HOME", home.path())
94+
.env("USERPROFILE", home.path())
95+
.output()
96+
.expect("run Cortex upgrade");
97+
98+
server.join().expect("server thread finished");
99+
100+
let stdout = String::from_utf8_lossy(&output.stdout);
101+
let stderr = String::from_utf8_lossy(&output.stderr);
102+
103+
assert!(
104+
output.status.success(),
105+
"upgrade command failed\nstdout:\n{stdout}\nstderr:\n{stderr}"
106+
);
107+
assert!(
108+
stdout.contains("fixed changelog repo URL"),
109+
"expected changelog content from corrected CortexLM/cortex URL\nstdout:\n{stdout}\nstderr:\n{stderr}"
110+
);
111+
assert!(
112+
!stderr.contains("Failed to fetch changelog"),
113+
"changelog fetch should not fail\nstdout:\n{stdout}\nstderr:\n{stderr}"
114+
);
115+
}

0 commit comments

Comments
 (0)