1use lazy_static::lazy_static;
2use url::Url;
3
4use crate::{hosting_provider::HostingProvider, permalink::ParsedGitRemote};
5
6lazy_static! {
7 static ref GITHUB_PULL_REQUEST_NUMBER: regex::Regex =
8 regex::Regex::new(r"\(#(\d+)\)$").unwrap();
9}
10
11#[derive(Clone, Debug)]
12pub struct PullRequest {
13 pub number: u32,
14 pub url: Url,
15}
16
17pub fn extract_pull_request(remote: &ParsedGitRemote, message: &str) -> Option<PullRequest> {
18 match remote.provider {
19 HostingProvider::Github => {
20 let line = message.lines().next()?;
21 let capture = GITHUB_PULL_REQUEST_NUMBER.captures(line)?;
22 let number = capture.get(1)?.as_str().parse::<u32>().ok()?;
23
24 let mut url = remote.provider.base_url();
25 let path = format!("/{}/{}/pull/{}", remote.owner, remote.repo, number);
26 url.set_path(&path);
27
28 Some(PullRequest { number, url })
29 }
30 _ => None,
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use unindent::Unindent;
37
38 use crate::{
39 hosting_provider::HostingProvider, permalink::ParsedGitRemote,
40 pull_request::extract_pull_request,
41 };
42
43 #[test]
44 fn test_github_pull_requests() {
45 let remote = ParsedGitRemote {
46 provider: HostingProvider::Github,
47 owner: "zed-industries",
48 repo: "zed",
49 };
50
51 let message = "This does not contain a pull request";
52 assert!(extract_pull_request(&remote, message).is_none());
53
54 // Pull request number at end of first line
55 let message = r#"
56 project panel: do not expand collapsed worktrees on "collapse all entries" (#10687)
57
58 Fixes #10597
59
60 Release Notes:
61
62 - Fixed "project panel: collapse all entries" expanding collapsed worktrees.
63 "#
64 .unindent();
65
66 assert_eq!(
67 extract_pull_request(&remote, &message)
68 .unwrap()
69 .url
70 .as_str(),
71 "https://github.com/zed-industries/zed/pull/10687"
72 );
73
74 // Pull request number in middle of line, which we want to ignore
75 let message = r#"
76 Follow-up to #10687 to fix problems
77
78 See the original PR, this is a fix.
79 "#
80 .unindent();
81 assert!(extract_pull_request(&remote, &message).is_none());
82 }
83}