66import re
77from typing import Optional
88
9+ from .github_repo_util import find_github_repo
910from .pullrequest import PullRequestId
1011from .pullrequeststore import PullRequestStore
1112
1213
1314def get_pull_request_for_context (
1415 store : PullRequestStore ,
16+ repo ,
1517 ctx ,
1618) -> Optional [PullRequestId ]:
1719 """Returns a pull request associated with a commit context, if any. Checks
@@ -20,20 +22,55 @@ def get_pull_request_for_context(
2022 """
2123 node = ctx .node ()
2224 pr = store .find_pull_request (node )
23- return pr if pr else _parse_github_pull_request_url (ctx .description ())
25+ return pr if pr else _parse_github_pull_request_url (ctx .description (), repo )
2426
2527
26- def _parse_github_pull_request_url (descr : str ) -> Optional [PullRequestId ]:
28+ def _parse_github_pull_request_url (descr : str , repo ) -> Optional [PullRequestId ]:
2729 r"""If the commit message has a comment in a special format that indicates
2830 it is associated with a GitHub pull request, returns the corresponding
2931 PullRequestId.
3032
33+ Match the number at the end of the title.
34+ >>> from .testutil import FakeGitHubRepo
35+ >>> gh_repo = FakeGitHubRepo(name="dotslash")
36+ >>> commit_msg = 'Document experimental `fetch` subcommand (#24)\nSummary:\nDocument...'
37+ >>> _parse_github_pull_request_url(commit_msg, gh_repo)
38+ PullRequestId(hostname='github.com', owner='facebook', name='dotslash', number=24)
39+
40+ Should work with a single line title.
41+ >>> commit_msg = 'Document experimental `fetch` subcommand (#24)'
42+ >>> _parse_github_pull_request_url(commit_msg, gh_repo)
43+ PullRequestId(hostname='github.com', owner='facebook', name='dotslash', number=24)
44+
45+ Does not match if the pattern appears after the first line.
46+ >>> commit_msg = 'TITLE\nDocument experimental `fetch` subcommand (#24)\nSummary:\nDocument...'
47+ >>> _parse_github_pull_request_url(commit_msg, gh_repo) is None
48+ True
49+
50+ Match the "Pull Request resolved" text.
3151 >>> descr = 'foo\nPull Request resolved: https://github.com/bolinfest/ghstack-testing/pull/71\nbar'
32- >>> _parse_github_pull_request_url(descr)
52+ >>> _parse_github_pull_request_url(descr, gh_repo )
3353 PullRequestId(hostname='github.com', owner='bolinfest', name='ghstack-testing', number=71)
34- >>> _parse_github_pull_request_url('') is None
54+
55+ Test a trivial "no match" case.
56+ >>> _parse_github_pull_request_url('', gh_repo) is None
3557 True
3658 """
59+ # The default for "squash and merge" in the GitHub pull request flow appears
60+ # to put the pull request number at the end of the first line of the commit
61+ # message, so check that first.
62+ match = re .search (r'^.*\(#([1-9][0-9]*)\)\r?(\n|$)' , descr )
63+ if match :
64+ result = find_github_repo (repo )
65+ if result .is_ok ():
66+ github_repo = result .unwrap ()
67+ return PullRequestId (
68+ hostname = github_repo .hostname ,
69+ owner = github_repo .owner ,
70+ name = github_repo .name ,
71+ number = int (match .group (1 )),
72+ )
73+
3774 # This is the format used by ghstack, though other variants may be supported
3875 # in the future.
3976 match = re .search (
0 commit comments