crates_index_diff/index/diff/
github.rs1use reqwest::{StatusCode, Url};
2
3#[derive(Debug)]
4pub(crate) enum FastPath {
5 UpToDate,
6 NeedsFetch,
7 Indeterminate,
8}
9
10fn user_and_repo_from_url_if_github(fetch_url: &gix::Url) -> Option<(String, String)> {
12 let url = Url::parse(&fetch_url.to_string()).ok()?;
13 if !(url.host_str() == Some("github.com")) {
14 return None;
15 }
16
17 let mut pieces = url.path_segments()?;
20 let username = pieces.next()?;
21 let repository = pieces.next()?;
22 let repository = repository.strip_suffix(".git").unwrap_or(repository);
23 if pieces.next().is_some() {
24 return None;
25 }
26 Some((username.to_string(), repository.to_string()))
27}
28
29pub(crate) fn has_changes(
45 fetch_url: &gix::Url,
46 last_seen_reference: &gix::ObjectId,
47 branch_name: &str,
48) -> Result<FastPath, reqwest::Error> {
49 let (username, repository) = match user_and_repo_from_url_if_github(fetch_url) {
50 Some(url) => url,
51 None => return Ok(FastPath::Indeterminate),
52 };
53
54 let url = format!(
55 "https://api.github.com/repos/{}/{}/commits/{}",
56 username, repository, branch_name,
57 );
58
59 let client = reqwest::blocking::Client::builder()
60 .user_agent("crates-index-diff")
61 .build()?;
62 let response = client
63 .get(&url)
64 .header("Accept", "application/vnd.github.sha")
65 .header("If-None-Match", format!("\"{}\"", last_seen_reference))
66 .send()?;
67
68 let status = response.status();
69 if status == StatusCode::NOT_MODIFIED {
70 Ok(FastPath::UpToDate)
71 } else if status.is_success() {
72 Ok(FastPath::NeedsFetch)
73 } else {
74 Ok(FastPath::Indeterminate)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use std::convert::TryFrom;
85
86 #[test]
87 fn test_github_http_url() {
88 let (user, repo) = user_and_repo_from_url_if_github(
89 &gix::Url::try_from("https://github.com/some_user/some_repo.git").unwrap(),
90 )
91 .unwrap();
92 assert_eq!(user, "some_user");
93 assert_eq!(repo, "some_repo");
94 }
95
96 #[test]
97 fn test_github_ssh_url() {
98 let (user, repo) = user_and_repo_from_url_if_github(
99 &gix::Url::try_from("ssh://git@github.com/some_user/some_repo.git").unwrap(),
100 )
101 .unwrap();
102 assert_eq!(user, "some_user");
103 assert_eq!(repo, "some_repo");
104 }
105
106 #[test]
107 fn test_non_github_url() {
108 assert!(user_and_repo_from_url_if_github(
109 &gix::Url::try_from("https://not_github.com/some_user/some_repo.git").unwrap(),
110 )
111 .is_none());
112 }
113}