diff --git a/ghpr-api.el b/ghpr-api.el index 94d4060..1cfeb21 100644 --- a/ghpr-api.el +++ b/ghpr-api.el @@ -49,7 +49,11 @@ Returns the token string if found, nil otherwise." (username . ,(alist-get 'login user)) (author . ,(alist-get 'login user)) (base_sha . ,(alist-get 'sha base)) + (base_ref . ,(alist-get 'ref base)) (head_sha . ,(alist-get 'sha head)) + (head_ref . ,(alist-get 'ref head)) + (head_repo . ,(alist-get 'repo head)) + (head_user . ,(alist-get 'user head)) (merge_commit_sha . ,(alist-get 'merge_commit_sha pr))))) (defun ghpr--parse-api-pr-list (pr-list) diff --git a/ghpr-repo.el b/ghpr-repo.el index 2e60bb4..c0ae781 100644 --- a/ghpr-repo.el +++ b/ghpr-repo.el @@ -41,6 +41,55 @@ Returns nil if origin remote doesn't exist or is not a GitHub repository." (when (string-match "github\\.com[:/]\\([^/]+/[^/.]+\\)" origin-url) (match-string 1 origin-url))))) +(defun ghpr--is-fork-pr-p (pr-metadata) + "Return t if PR is from a fork, nil if from same repository. +PR-METADATA should contain head_repo and head_user information." + (let ((head-repo (alist-get 'head_repo pr-metadata)) + (head-user (alist-get 'head_user pr-metadata)) + (origin-repo-name (ghpr--get-repo-name))) + (when (and head-repo head-user origin-repo-name) + (let ((head-repo-full-name (alist-get 'full_name head-repo)) + (head-user-login (alist-get 'login head-user))) + (not (string= head-repo-full-name origin-repo-name)))))) + +(defun ghpr--get-or-add-remote (pr-metadata) + "Get or add the remote for the PR's head repository. +Returns the remote name to use for fetching the PR branch." + (let* ((head-repo (alist-get 'head_repo pr-metadata)) + (head-user (alist-get 'head_user pr-metadata)) + (head-user-login (alist-get 'login head-user)) + (head-repo-clone-url (alist-get 'clone_url head-repo)) + (remote-name head-user-login)) + + (if (ghpr--is-fork-pr-p pr-metadata) + (progn + (unless (magit-remote-p remote-name) + (magit-remote-add remote-name head-repo-clone-url)) + remote-name) + "origin"))) + +(defun ghpr--checkout-pr-branch (pr-metadata) + "Check out the PR branch using Magit. +Fetches the branch from appropriate remote if needed, then checks it out. +PR-METADATA should contain head_ref, head_sha, and repository information." + (let* ((head-ref (alist-get 'head_ref pr-metadata)) + (head-sha (alist-get 'head_sha pr-metadata)) + (pr-number (alist-get 'number pr-metadata)) + (remote-name (ghpr--get-or-add-remote pr-metadata)) + (remote-branch-ref (format "%s/%s" remote-name head-ref)) + (local-branch-name head-ref)) + + (unless head-ref + (error "PR metadata missing head branch reference")) + + (message "Fetching PR branch from %s..." remote-name) + (magit-fetch-branch remote-name head-ref local-branch-name) + + (message "Checking out PR branch: %s" local-branch-name) + (magit-checkout local-branch-name) + + (message "Checked out PR #%s branch: %s" pr-number local-branch-name))) + (provide 'ghpr-repo) ;;; ghpr-repo.el ends here diff --git a/ghpr-review.el b/ghpr-review.el index 3e73d3f..3c46df6 100644 --- a/ghpr-review.el +++ b/ghpr-review.el @@ -35,6 +35,7 @@ (require 'magit-git) (require 'ghpr-api) +(require 'ghpr-repo) (require 'ghpr-utils) (defface ghpr-review-added-line @@ -82,6 +83,7 @@ (define-key prefix-map (kbd "C-c") 'ghpr-review-comment) (define-key prefix-map (kbd "C-a") 'ghpr-review-approve) (define-key prefix-map (kbd "C-r") 'ghpr-review-reject-changes) + (define-key prefix-map (kbd "C-o") 'ghpr-review-checkout-branch) (define-key map (kbd "C-c") prefix-map) map) "Keymap for `ghpr-review-mode'.") @@ -401,6 +403,13 @@ Collects review body and inline comments from current buffer." (interactive) (ghpr--submit-review "REQUEST_CHANGES")) +(defun ghpr-review-checkout-branch () + "Check out the PR branch using Magit." + (interactive) + (unless ghpr--review-pr-metadata + (error "No PR metadata found in buffer")) + (ghpr--checkout-pr-branch ghpr--review-pr-metadata)) + (provide 'ghpr-review) ;;; ghpr-review.el ends here