Skip to content

Commit 4b0e263

Browse files
authored
feat: emit help messages for github pull request url in dependency (#16207)
Succeeding #15003. Piror to this, using a GitHub pull request URLs as dependencies would just fail because of HTTP errors as it's simply not a git repository. This PR implements some help messages on such cases for users to know why it's failing, and how to fix it. Close #15001.
2 parents bee2529 + ca2973a commit 4b0e263

File tree

4 files changed

+146
-11
lines changed

4 files changed

+146
-11
lines changed

src/cargo/sources/git/oxide.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use tracing::debug;
1919
pub fn with_retry_and_progress(
2020
repo_path: &std::path::Path,
2121
gctx: &GlobalContext,
22+
repo_remote_url: &str,
2223
cb: &(
2324
dyn Fn(
2425
&std::path::Path,
@@ -54,7 +55,7 @@ pub fn with_retry_and_progress(
5455
*urls.borrow_mut() = Some(url.to_owned());
5556
},
5657
);
57-
amend_authentication_hints(res, urls.get_mut().take())
58+
amend_authentication_hints(res, repo_remote_url, urls.get_mut().take())
5859
});
5960
translate_progress_to_bar(&mut progress_bar, root, is_shallow)?;
6061
thread.join().expect("no panic in scoped thread")
@@ -180,6 +181,7 @@ fn translate_progress_to_bar(
180181

181182
fn amend_authentication_hints(
182183
res: Result<(), crate::sources::git::fetch::Error>,
184+
remote_url: &str,
183185
last_url_for_authentication: Option<gix::bstr::BString>,
184186
) -> CargoResult<()> {
185187
let Err(err) = res else { return Ok(()) };
@@ -189,6 +191,7 @@ fn amend_authentication_hints(
189191
) => Some(err),
190192
_ => None,
191193
};
194+
192195
if let Some(e) = e {
193196
let auth_message = match e {
194197
gix::protocol::handshake::Error::Credentials(_) => {
@@ -203,10 +206,14 @@ fn amend_authentication_hints(
203206
.into()
204207
}
205208
gix::protocol::handshake::Error::Transport(_) => {
206-
let msg = concat!(
207-
"network failure seems to have happened\n",
208-
"if a proxy or similar is necessary `net.git-fetch-with-cli` may help here\n",
209-
"https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli"
209+
let msg = format!(
210+
concat!(
211+
"network failure seems to have happened\n",
212+
"if a proxy or similar is necessary `net.git-fetch-with-cli` may help here\n",
213+
"https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli",
214+
"{}"
215+
),
216+
super::utils::note_github_pull_request(remote_url).unwrap_or_default()
210217
);
211218
return Err(anyhow::Error::from(err).context(msg));
212219
}

src/cargo/sources/git/utils.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,12 +798,14 @@ where
798798
| ErrorClass::FetchHead
799799
| ErrorClass::Ssh
800800
| ErrorClass::Http => {
801-
let mut msg = "network failure seems to have happened\n".to_string();
802-
msg.push_str(
803-
"if a proxy or similar is necessary `net.git-fetch-with-cli` may help here\n",
804-
);
805-
msg.push_str(
806-
"https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli",
801+
let msg = format!(
802+
concat!(
803+
"network failure seems to have happened\n",
804+
"if a proxy or similar is necessary `net.git-fetch-with-cli` may help here\n",
805+
"https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli",
806+
"{}"
807+
),
808+
note_github_pull_request(url).unwrap_or_default()
807809
);
808810
err = err.context(msg);
809811
}
@@ -1142,6 +1144,7 @@ fn fetch_with_gitoxide(
11421144
let res = oxide::with_retry_and_progress(
11431145
git2_repo.path(),
11441146
gctx,
1147+
remote_url,
11451148
&|repo_path,
11461149
should_interrupt,
11471150
mut progress,
@@ -1589,6 +1592,33 @@ fn is_github(url: &Url) -> bool {
15891592
url.host_str() == Some("github.com")
15901593
}
15911594

1595+
// Give some messages on GitHub PR URL given as is
1596+
pub(crate) fn note_github_pull_request(url: &str) -> Option<String> {
1597+
if let Ok(url) = url.parse::<Url>()
1598+
&& is_github(&url)
1599+
{
1600+
let path_segments = url
1601+
.path_segments()
1602+
.map(|p| p.into_iter().collect::<Vec<_>>())
1603+
.unwrap_or_default();
1604+
if let [owner, repo, "pull", pr_number, ..] = path_segments[..] {
1605+
let repo_url = format!("https://github.com/{owner}/{repo}.git");
1606+
let rev = format!("refs/pull/{pr_number}/head");
1607+
return Some(format!(
1608+
concat!(
1609+
"\n\nnote: GitHub url {} is not a repository. \n",
1610+
"help: Replace the dependency with \n",
1611+
" `git = \"{}\" rev = \"{}\"` \n",
1612+
" to specify pull requests as dependencies' revision."
1613+
),
1614+
url, repo_url, rev
1615+
));
1616+
}
1617+
}
1618+
1619+
None
1620+
}
1621+
15921622
/// Whether a `rev` looks like a commit hash (ASCII hex digits).
15931623
fn looks_like_commit_hash(rev: &str) -> bool {
15941624
rev.len() >= 7 && rev.chars().all(|ch| ch.is_ascii_hexdigit())

tests/testsuite/bad_config.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,6 +2259,47 @@ Caused by:
22592259
.run();
22602260
}
22612261

2262+
#[cargo_test(public_network_test)]
2263+
fn github_pull_request_url() {
2264+
let p = project()
2265+
.file(
2266+
"Cargo.toml",
2267+
r#"
2268+
[package]
2269+
name = "foo"
2270+
version = "0.0.0"
2271+
edition = "2015"
2272+
authors = []
2273+
2274+
[dependencies.bar]
2275+
git = "https://github.com/rust-lang/does-not-exist/pull/123"
2276+
"#,
2277+
)
2278+
.file("src/lib.rs", "")
2279+
.build();
2280+
2281+
p.cargo("check -v")
2282+
.with_status(101)
2283+
.with_stderr_data(str![[r#"
2284+
[UPDATING] git repository `https://github.com/rust-lang/does-not-exist/pull/123`
2285+
...
2286+
[ERROR] failed to get `bar` as a dependency of package `foo v0.0.0 ([ROOT]/foo)`
2287+
2288+
Caused by:
2289+
failed to load source for dependency `bar`
2290+
2291+
Caused by:
2292+
Unable to update https://github.com/rust-lang/does-not-exist/pull/123
2293+
...
2294+
[NOTE] GitHub url https://github.com/rust-lang/does-not-exist/pull/123 is not a repository.
2295+
[HELP] Replace the dependency with
2296+
`git = "https://github.com/rust-lang/does-not-exist.git" rev = "refs/pull/123/head"`
2297+
to specify pull requests as dependencies' revision.
2298+
...
2299+
"#]])
2300+
.run();
2301+
}
2302+
22622303
#[cargo_test]
22632304
fn fragment_in_git_url() {
22642305
let p = project()

tests/testsuite/patch.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,63 @@ fn patch_to_git() {
357357
.run();
358358
}
359359

360+
#[cargo_test(public_network_test)]
361+
fn patch_to_git_pull_request() {
362+
Package::new("bar", "0.1.0").publish();
363+
364+
let p = project()
365+
.file(
366+
"Cargo.toml",
367+
r#"
368+
[package]
369+
name = "foo"
370+
version = "0.0.1"
371+
edition = "2015"
372+
authors = []
373+
374+
[dependencies]
375+
bar = "0.1"
376+
377+
[patch.crates-io]
378+
bar = { git = 'https://github.com/rust-lang/does-not-exist/pull/123' }
379+
"#,
380+
)
381+
.file(
382+
"src/lib.rs",
383+
"extern crate bar; pub fn foo() { bar::bar(); }",
384+
)
385+
.build();
386+
387+
p.cargo("check -v")
388+
.with_status(101)
389+
.with_stderr_data(format!(
390+
r#"[UPDATING] git repository `https://github.com/rust-lang/does-not-exist/pull/123`
391+
...
392+
[ERROR] failed to load source for dependency `bar`
393+
394+
Caused by:
395+
Unable to update https://github.com/rust-lang/does-not-exist/pull/123
396+
397+
Caused by:
398+
failed to clone into: [ROOT]/home/.cargo/git/db/123-[HASH]
399+
400+
Caused by:
401+
network failure seems to have happened
402+
if a proxy or similar is necessary `net.git-fetch-with-cli` may help here
403+
https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli
404+
405+
[NOTE] GitHub url https://github.com/rust-lang/does-not-exist/pull/123 is not a repository.
406+
[HELP] Replace the dependency with
407+
`git = "https://github.com/rust-lang/does-not-exist.git" rev = "refs/pull/123/head"`
408+
to specify pull requests as dependencies' revision.
409+
410+
Caused by:
411+
...
412+
"#
413+
))
414+
.run();
415+
}
416+
360417
#[cargo_test]
361418
fn unused() {
362419
Package::new("bar", "0.1.0").publish();

0 commit comments

Comments
 (0)