Skip to content

Commit

Permalink
Implement query parameter when searching for PR's
Browse files Browse the repository at this point in the history
Fixes #1937

Add `query` argument to `gs_github_pull_request` (default: "") to filter
the list of PR's we fetch.  As the search API does return a subset of
the information we need, query the full PR response in a second step
(but in the background using a future).

The query parameter is a string and can be basically anything a user
would also type in on Github's website.

Interesting candidates are e.g. "involves:@me" which is also added to
the Command Palette.
  • Loading branch information
kaste committed Nov 27, 2024
1 parent c0e73ac commit 8f3f6a3
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 7 deletions.
7 changes: 6 additions & 1 deletion Default.sublime-commands
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,14 @@
"command": "gs_github_open_repo"
},
{
"caption": "github: review pull request",
"caption": "github: review pull request (show: all)",
"command": "gs_github_pull_request"
},
{
"caption": "github: review pull request (show: mine)",
"command": "gs_github_pull_request",
"args": { "query": "involves:@me" }
},
{
"caption": "github: set remote for integration",
"command": "gs_github_configure_remote"
Expand Down
33 changes: 27 additions & 6 deletions github/commands/pull_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
from ...common import interwebs
from ...common import util
from ...core.commands.push import gs_push_to_branch_name
from ...core.fns import filter_
from ...core.ui_mixins.quick_panel import show_paginated_panel
from ...core.ui_mixins.input_panel import show_single_line_input_panel
from ...core.view import replace_view_content
from GitSavvy.core.base_commands import GsWindowCommand
from GitSavvy.core.runtime import on_worker
from GitSavvy.core.runtime import on_worker, run_as_future


__all__ = (
Expand All @@ -27,18 +28,29 @@
class gs_github_pull_request(GsWindowCommand, git_mixins.GithubRemotesMixin):

"""
Display open pull requests on the base repo. When a pull request is selected,
Display pull requests on the base repo. When a pull request is selected,
allow the user to 1) checkout the PR as detached HEAD, 2) checkout the PR as
a local branch, 3) view the PR's diff, or 4) open the PR in the browser.
By default, all "open" pull requests are displayed. This can be customized
using the `query` arg which is of the same query format as in the Web UI of
Github. Note that "repo:", "type:", and "state:" are prefilled if omitted.
"""

@on_worker
def run(self):
def run(self, query=""):
self.remotes = self.get_remotes()
self.base_remote_name = self.get_integrated_remote_name(self.remotes)
self.base_remote_url = self.remotes[self.base_remote_name]
self.base_remote = github.parse_remote(self.base_remote_url)
self.pull_requests = github.get_pull_requests(self.base_remote)
self.base_remote = repository = github.parse_remote(self.base_remote_url)

query_ = " ".join(filter_((
f"repo:{repository.owner}/{repository.repo}" if "repo:" not in query else None,
"type:pr" if "type:" not in query else None,
"state:open" if "state:" not in query else None,
query.strip()
)))
self.pull_requests = github.search_pull_requests(self.base_remote, query_)

pp = show_paginated_panel(
self.pull_requests,
Expand Down Expand Up @@ -67,7 +79,7 @@ def on_select_pr(self, pr):
if not pr:
return

self.pr = pr
self.pr_ = run_as_future(github.get_pull_request, pr["number"], self.base_remote)
self.window.show_quick_panel(
["Checkout as detached HEAD.",
"Checkout as local branch.",
Expand All @@ -81,6 +93,15 @@ def on_select_action(self, idx):
if idx == -1:
return

# Note that the request starts in `on_select_pr`. So the actual wait time includes the
# time we wait for the user to take action.
timeout = 4.0
try:
self.pr = self.pr_.result(timeout)
except TimeoutError:
self.window.status_message(f"Timeout: could not fetch the PR details within {timeout} seconds.")
return

owner = self.pr["head"]["repo"]["owner"]["login"]

if owner == self.base_remote.owner:
Expand Down
22 changes: 22 additions & 0 deletions github/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,28 @@ def iteratively_query_github(
get_pull_requests = partial(iteratively_query_github, "/repos/{owner}/{repo}/pulls")


def search_pull_requests(repository: GitHubRepo, q: str):
return iteratively_query_github("/search/issues", repository, query={"q": q}, yield_="items")


def get_pull_request(nr: str | int, github_repo: GitHubRepo):
return get_from_github(f"/repos/{{owner}}/{{repo}}/pulls/{nr}", github_repo)


def get_from_github(api_url_template: str, github_repo: GitHubRepo):
fqdn, path = github_api_url(api_url_template, github_repo)
auth = (github_repo.token, "x-oauth-basic") if github_repo.token else None

response = interwebs.get(
fqdn, 443, path, https=True, auth=auth,
headers={
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28"
})
validate_response(response)
return response.payload


def post_to_github(api_url_template, github_repo, payload=None):
"""
Takes a URL template that takes `owner` and `repo` template variables
Expand Down

0 comments on commit 8f3f6a3

Please sign in to comment.