Skip to main content

worktree_io/issue/parse/
mod.rs

1mod azure;
2mod centy;
3mod gh;
4mod github;
5mod shorthand;
6mod worktree_url;
7
8use anyhow::{bail, Result};
9
10use super::{DeepLinkOptions, IssueRef};
11
12impl IssueRef {
13    /// Parse any of the supported input formats:
14    /// - `https://github.com/owner/repo/issues/42`
15    /// - `worktree://open?owner=X&repo=Y&issue=42`
16    /// - `worktree://open?url=<encoded-github-url>`
17    /// - `worktree://open?owner=X&repo=Y&linear_id=<uuid>`
18    /// - `owner/repo#42`
19    /// - `owner/repo@<linear-uuid>`
20    /// - `centy:<number>` (context-aware: finds nearest `.centy/` ancestor)
21    /// - `gh:<number>` (context-aware: resolves against the `origin` GitHub remote)
22    ///
23    /// # Errors
24    ///
25    /// Returns an error if `s` does not match any supported format or if the
26    /// extracted values (e.g. issue number) are invalid.
27    pub fn parse(s: &str) -> Result<Self> {
28        let s = s.trim();
29
30        if s.starts_with("worktree://") {
31            let (issue, _opts) = worktree_url::parse_worktree_url(s)?;
32            return Ok(issue);
33        }
34
35        if s.starts_with("https://github.com") || s.starts_with("http://github.com") {
36            return github::parse_github_url(s);
37        }
38
39        if s.starts_with("https://dev.azure.com") || s.starts_with("http://dev.azure.com") {
40            return azure::parse_azure_devops_url(s);
41        }
42
43        if s.starts_with("centy:") {
44            return centy::parse_centy(s);
45        }
46
47        if s.starts_with("gh:") {
48            return gh::parse_gh(s);
49        }
50
51        if let Some(result) = shorthand::try_parse_shorthand(s) {
52            return result;
53        }
54
55        bail!(
56            "Could not parse issue reference: {s:?}\n\
57             Supported formats:\n\
58             - https://github.com/owner/repo/issues/42\n\
59             - https://dev.azure.com/org/project/_workitems/edit/42\n\
60             - worktree://open?owner=owner&repo=repo&issue=42\n\
61             - worktree://open?owner=owner&repo=repo&linear_id=<uuid>\n\
62             - worktree://open?org=org&project=project&repo=repo&work_item_id=42\n\
63             - owner/repo#42\n\
64             - owner/repo@<linear-uuid>\n\
65             - org/project/repo!42\n\
66             - centy:<number>\n\
67             - gh:<number>"
68        )
69    }
70
71    /// Like [`parse`] but also returns any [`DeepLinkOptions`] embedded in a
72    /// `worktree://` URL (e.g. the `editor` query param).
73    ///
74    /// # Errors
75    ///
76    /// Returns an error if `s` cannot be parsed as a valid issue reference.
77    pub fn parse_with_options(s: &str) -> Result<(Self, DeepLinkOptions)> {
78        let s = s.trim();
79        if s.starts_with("worktree://") {
80            return worktree_url::parse_worktree_url(s);
81        }
82        Ok((Self::parse(s)?, DeepLinkOptions::default()))
83    }
84}