From fbf952b215f1efd171bf7cc5fb4f3caf9159fede Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Tue, 27 Sep 2016 16:23:52 +0200 Subject: [PATCH] Move from magit-gh-pulls to magithub --- .../magit-gh-pulls-autoloads.el | 27 - .../magit-gh-pulls-pkg.el | 1 - .../magit-gh-pulls.el | 608 ------------------ .../magithub-autoloads.el | 17 + elpa/magithub-20160926.2044/magithub-cache.el | 67 ++ elpa/magithub-20160926.2044/magithub-ci.el | 197 ++++++ elpa/magithub-20160926.2044/magithub-core.el | 149 +++++ elpa/magithub-20160926.2044/magithub-issue.el | 179 ++++++ elpa/magithub-20160926.2044/magithub-pkg.el | 12 + elpa/magithub-20160926.2044/magithub.el | 207 ++++++ 10 files changed, 828 insertions(+), 636 deletions(-) delete mode 100644 elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-autoloads.el delete mode 100644 elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-pkg.el delete mode 100644 elpa/magit-gh-pulls-20160513.310/magit-gh-pulls.el create mode 100644 elpa/magithub-20160926.2044/magithub-autoloads.el create mode 100644 elpa/magithub-20160926.2044/magithub-cache.el create mode 100644 elpa/magithub-20160926.2044/magithub-ci.el create mode 100644 elpa/magithub-20160926.2044/magithub-core.el create mode 100644 elpa/magithub-20160926.2044/magithub-issue.el create mode 100644 elpa/magithub-20160926.2044/magithub-pkg.el create mode 100644 elpa/magithub-20160926.2044/magithub.el diff --git a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-autoloads.el b/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-autoloads.el deleted file mode 100644 index c318b04..0000000 --- a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-autoloads.el +++ /dev/null @@ -1,27 +0,0 @@ -;;; magit-gh-pulls-autoloads.el --- automatically extracted autoloads -;; -;;; Code: -(add-to-list 'load-path (or (file-name-directory #$) (car load-path))) - -;;;### (autoloads nil "magit-gh-pulls" "magit-gh-pulls.el" (22387 -;;;;;; 29358 559405 127000)) -;;; Generated autoloads from magit-gh-pulls.el - -(autoload 'magit-gh-pulls-mode "magit-gh-pulls" "\ -Pull requests support for Magit - -\(fn &optional ARG)" t nil) - -(autoload 'turn-on-magit-gh-pulls "magit-gh-pulls" "\ -Unconditionally turn on `magit-pulls-mode'. - -\(fn)" nil nil) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; End: -;;; magit-gh-pulls-autoloads.el ends here diff --git a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-pkg.el b/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-pkg.el deleted file mode 100644 index 9cd1d70..0000000 --- a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls-pkg.el +++ /dev/null @@ -1 +0,0 @@ -(define-package "magit-gh-pulls" "20160513.310" "GitHub pull requests extension for Magit" '((emacs "24") (gh "0.9.1") (magit "2.1.0") (pcache "0.2.3") (s "1.6.1")) :url "https://github.com/sigma/magit-gh-pulls" :keywords '("git" "tools")) diff --git a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls.el b/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls.el deleted file mode 100644 index baf5acd..0000000 --- a/elpa/magit-gh-pulls-20160513.310/magit-gh-pulls.el +++ /dev/null @@ -1,608 +0,0 @@ -;;; magit-gh-pulls.el --- GitHub pull requests extension for Magit - -;; Copyright (C) 2011-2015 Yann Hodique, Alexander Yakushev - -;; Author: Yann Hodique -;; Keywords: git tools -;; Package-Version: 20160513.310 -;; Version: 0.5.2 -;; URL: https://github.com/sigma/magit-gh-pulls -;; Package-Requires: ((emacs "24") (gh "0.9.1") (magit "2.1.0") (pcache "0.2.3") (s "1.6.1")) - -;; This file is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2, or (at your option) -;; any later version. - -;; This file is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs; see the file COPYING. If not, write to -;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. - -;;; Commentary: - -;; This is a Magit extension for manipulating GitHub pull requests - -;; No configuration is needed in the repository if any of your remotes contain a -;; URL to Github's remote repository. If for some reason you don't have any -;; Github remotes in your config, you can specify username and repository -;; explicitly: - -;; $ git config magit.gh-pulls-repo / # your github repository - -;; Add these lines to your init.el: - -;; (require 'magit-gh-pulls) -;; (add-hook 'magit-mode-hook 'turn-on-magit-gh-pulls) - -;; These are the bindings for pull requests, defined in magit-gh-pulls-mode-map: -;; # g --- refreshes the list of pull requests -;; # f --- fetches the commits associated with the pull request at point -;; # b --- helps you creating a topic branch from a review request -;; # m --- merges the PR on top of the current branch -;; # c --- creates a PR from the current branch -;; # o --- opens a pull request on GitHub in your default browser - -;; Then, you can do whatever you want with the commit objects associated with -;; the pull request (merge, cherry-pick, diff, ...) - -;; When you create a new pull request, you can enable -w option to automatically -;; open it on GitHub in your default browser. - -;;; Code: - -(require 'eieio) - -(require 'magit) -(require 'git-commit) -(require 'gh) -(require 'gh-pulls) -(require 'pcache) -(require 's) -(require 'cl-lib) - -(defgroup magit-gh-pulls nil - "Github.com pull-requests for Magit." - :group 'magit-extensions) - -(defcustom magit-gh-pulls-open-new-pr-in-browser nil - "DEPRECATED: use magit switch instead." - :group 'magit-gh-pulls - :type 'boolean) - -(defvar magit-gh-pulls-maybe-filter-pulls 'identity - "Filter function which should validate pulls you want to be - viewed in magit. It receives a list of pull requests and should - return a list of pull requests.") - -(defvar magit-gh-pulls-collapse-commits t - "Collapse commits in pull requests listing.") - -(defvar magit-gh-pulls-pull-detail-limit 10 - "Pull in additional information for each pull request in the - status buffer only if the total number of open PRs is <= - this number. Additional information includes individual - commits in each PR and highlighting based on the merge - status of the PR. Increasing this number may adversely - affect performance on repos with many PRs.") - -(defvar-local magit-gh-pulls-previous-winconf nil) - -(defvar magit-gh-pulls-editor-mode-map - (let ((map (make-keymap))) - (define-key map (kbd "C-c C-c") 'magit-gh-pulls-pull-editor-finish) - (define-key map (kbd "C-c C-k") 'magit-gh-pulls-pull-editor-quit) - map)) - -(define-derived-mode magit-gh-pulls-editor-mode text-mode "Magit GitHub Pulls Editor" - (font-lock-add-keywords nil (git-commit-mode-font-lock-keywords) t)) - -(easy-menu-define magit-gh-pulls-editor-mode-menu magit-gh-pulls-editor-mode-map - "Magit GitHub Pulls Editor Menu" - '("Magit GitHub Pulls" - ["Submit Pull Request" magit-gh-pulls-pull-editor-finish t] - ["Cancel" magit-gh-pulls-pull-editor-quit t])) - -(defun magit-gh-pulls-get-api () - (gh-pulls-api "api" :sync t :num-retries 1 :cache (gh-cache "cache"))) - -(defun magit-gh-pulls-get-repo-from-config () - "Return (user . project) pair read from magit.gh-pulls-repo -config option." - (let* ((cfg (magit-get "magit" "gh-pulls-repo"))) - (when cfg - (let* ((split (split-string cfg "/"))) - (cons (car split) (cadr split)))))) - - -;;Find all the Hostname Lines until we hit the end of config-lines or the -;;next Host line. Return '(remaining-config-lines list-of-hostnames) -(defun magit-gh-pulls-collect-hostnames (config-lines) - (let ((cur-line (car config-lines)) - (rest config-lines) - (result '())) - (while (and cur-line (not (string= (cadr cur-line) "Host"))) - (setq result (cons (cadr (cdr cur-line)) result)) - (setq rest (cdr rest)) - (setq cur-line (car rest))) - (list rest result))) - - -(defun magit-gh-pulls-get-host-hostnames (config-lines) - (let (result-alist - (curline (car config-lines)) - (rest-lines (cdr config-lines))) - (while rest-lines - (if (string= (cadr curline) "Host") - (let ((hosts (s-split "\\s*" (cadr (cdr curline)))) ;;List of the host aliases - (rest-result (magit-gh-pulls-collect-hostnames rest-lines))) - (dolist (host hosts) - ;;Host must be lowercase because the url parser lowercases the string - (setq result-alist (cons (cons (downcase host) (cadr rest-result)) result-alist))) - (setq curline (caar rest-result)) - (setq rest-lines (cdar rest-result))) - (progn - (setq curline (car rest-lines)) - (setq rest-lines (cdr rest-lines))))) - result-alist)) - -(defun -magit-gh-pulls-filter-and-split-host-lines (lines) - (delq nil - (mapcar (lambda (line) - (s-match "^[ \t]*\\(Host\\|HostName\\|Hostname\\)[ \t]+\\(.+\\)$" line)) - lines))) - - -;; Port of github/hub's SSHConfig -(defun magit-gh-pulls-get-ssh-config-hosts () - (let* ((file-lines (mapcar (lambda (path) - (if (file-exists-p path) - (with-temp-buffer - (insert-file-contents path) - (split-string (buffer-string) "\n" t)) - '())) - (list - (concat (file-name-as-directory (getenv "HOME")) ".ssh/config") - "/etc/ssh_config" - "/etc/ssh/ssh_config"))) - (all-lines (apply #'append file-lines)) - (matched-lines (-magit-gh-pulls-filter-and-split-host-lines all-lines))) - (magit-gh-pulls-get-host-hostnames matched-lines))) - - -;; Port of github/hub's ParseURL, with modifications to align with existing parse-url -(defun magit-gh-pulls-parse-url (url ssh-config-hosts) - (let* ((fixed-url (if (and (not (s-matches? "^[a-zA-Z_-]+://" url)) - (s-matches? ":" url) - (not (s-matches? "\\\\\\\\" url))) ;;Two literal backlashes - (concat "ssh://" (s-replace ":" "/" url)) - url)) - (parsed-url (url-generic-parse-url fixed-url)) - (ssh-host (when (string= (url-type parsed-url) "ssh") - (assoc (url-host parsed-url) ssh-config-hosts)))) - (when (and ssh-host (cadr ssh-host)) - (setf (url-host parsed-url) (cadr ssh-host))) - (when (and - (string= (url-host parsed-url) "github.com") - (s-matches? "\\(git\\|ssh\\|https?\\)" (url-type parsed-url))) - (let ((creds (s-match "/\\(.+\\)/\\([^/]+\\)/?$" (url-filename parsed-url)))) - (when creds - (cons (cadr creds) (s-chop-suffix ".git" (cadr (cdr creds))))))))) - - -(defun magit-gh-pulls-guess-repo-from-origin () - "Return (user . project) pair inferred from remotes in -.git/config." - (let ((creds nil) - (ssh-config-hosts (magit-gh-pulls-get-ssh-config-hosts))) - (dolist (remote (magit-git-lines "remote") creds) - (let ((parsed (magit-gh-pulls-parse-url - (magit-get "remote" remote "url") - ssh-config-hosts))) - (when parsed - (setq creds parsed)))))) - -(defun magit-gh-pulls-guess-repo () - "Return (user . project) pair obtained either from explicit -option, or inferred from remotes." - (or (magit-gh-pulls-get-repo-from-config) - (magit-gh-pulls-guess-repo-from-origin))) - -(defun magit-gh-pulls-requests-cached-p (api user proj) - "Returns T if the API request to the given USER and PROJ is cached." - (let ((cache-repo (format "/repos/%s/%s/pulls" user proj)) - (cached? nil)) - (pcache-map (oref api :cache) - (lambda (key _) (when (equal (car key) cache-repo) - (setq cached? t)))) - cached?)) - -(defun magit-gh-pulls-insert-gh-pulls () - (condition-case-unless-debug print-section - (progn - (let* ((repo (magit-gh-pulls-guess-repo))) - (when repo - (let* ((api (magit-gh-pulls-get-api)) - (user (car repo)) - (proj (cdr repo)) - (cached? (magit-gh-pulls-requests-cached-p api user proj)) - (stubs (when cached? - (funcall magit-gh-pulls-maybe-filter-pulls - (oref (gh-pulls-list api user proj) :data)))) - (num-total-stubs (length stubs)) - (i 0) - (branch (magit-get-current-branch))) - (when (or (> (length stubs) 0) (not cached?)) - (magit-insert-section (pulls) - (magit-insert-heading "Pull Requests:") - (dolist (stub stubs) - (cl-incf i) - (let* ((id (oref stub :number)) - (base-sha (oref (oref stub :base) :sha)) - (base-ref (oref (oref stub :base) :ref)) - (head-sha (oref (oref stub :head) :sha)) - ;; branch has been deleted in the meantime... - (invalid (equal (oref (oref stub :head) :ref) head-sha)) - (have-commits - (and (>= magit-gh-pulls-pull-detail-limit i) - (eql 0 (magit-git-exit-code "cat-file" "-e" base-sha)) - (eql 0 (magit-git-exit-code "cat-file" "-e" head-sha)))) - (applied (and have-commits - (magit-git-string "branch" branch - (format "--contains=%s" head-sha)))) - (heading - (format "[%s@%s] %s\n" - (propertize (number-to-string id) - 'face 'magit-tag) - (if (string= base-ref branch) - (propertize base-ref - 'face 'magit-branch-local) - base-ref) - (propertize - (oref stub :title) 'face - (cond (applied 'magit-cherry-equivalent) - (have-commits nil) - (invalid 'error) - (t 'italic))))) - (info (list user proj id))) - (cond - (have-commits - (magit-insert-section - (pull info magit-gh-pulls-collapse-commits) - (insert heading) - (magit-insert-heading) - (when (and have-commits (not applied)) - (magit-git-wash - (apply-partially 'magit-log-wash-log 'cherry) - "cherry" "-v" (magit-abbrev-arg) - base-sha head-sha)))) - (invalid - (magit-insert-section (invalid-pull info) - (insert heading))) - (t - (magit-insert-section (unfetched-pull info) - (insert heading)))))) - (when (not cached?) - (insert "Press `# g` to update the pull request list.\n\n")) - (when (> (length stubs) 0) - (insert "\n")))))))) - (error nil))) - -(defun magit-gh-pulls-guess-topic-name (req) - (let ((user (oref (oref req :user) :login)) - (topic (oref (oref req :head) :ref))) - (format "%s/%s" user topic))) - -(defun magit-gh-section-req-data (&optional section) - (oref (apply #'gh-pulls-get - (magit-gh-pulls-get-api) - (magit-section-value (or section (magit-current-section)))) - :data)) - -(defun magit-gh-pulls-diff-pull-request () - (interactive) - (magit-section-case - (pull - (let* ((req (magit-gh-section-req-data)) - (inhibit-magit-refresh t)) - (magit-diff (concat (oref (oref req :base) :sha) ".." - (oref (oref req :head) :sha)))) - (magit-refresh)) - (unfetched-pull - (error "Please fetch pull request commits first")) - (invalid-pull - (error "This pull request refers to invalid reference")))) - - -(defun magit-gh-pulls-create-branch () - (interactive) - (magit-section-case - (pull - (let* ((req (magit-gh-section-req-data)) - (branch (read-from-minibuffer - "Branch name: " (magit-gh-pulls-guess-topic-name req))) - (base (magit-read-branch-or-commit - "Branch base: " - (oref (oref req :base) :ref))) - (inhibit-magit-refresh t)) - (magit-branch-and-checkout branch base) - (magit-merge (oref (oref req :head) :sha))) - (magit-refresh)) - (unfetched-pull - (error "Please fetch pull request commits first")) - (invalid-pull - (error "This pull request refers to invalid reference")))) - -(defun magit-gh-pulls-merge-pull-request () - (interactive) - (magit-section-case - (pull - (let* ((req (magit-gh-section-req-data)) - (branch (magit-gh-pulls-guess-topic-name req)) - (base (oref (oref req :base) :ref)) - (inhibit-magit-refresh t)) - (magit-branch-and-checkout branch base) - (magit-merge (oref (oref req :head) :sha)) - (magit-checkout base) - (magit-merge branch (when (member "--no-ff" (magit-gh-pulls-arguments)) - '("--no-ff"))) - (magit-call-git "branch" "-D" branch)) - (magit-refresh)) - (unfetched-pull - (error "Please fetch pull request commits first")) - (invalid-pull - (error "This pull request refers to invalid reference")))) - -(defun magit-gh-pulls-fetch-commits () - (interactive) - (magit-section-case - (unfetched-pull - (let* ((req (magit-gh-section-req-data)) - (head (oref req :head))) - (magit-run-git "fetch" (oref (oref head :repo) :ssh-url) - (oref head :ref)))) - (pull nil) - (invalid-pull - (error "This pull request refers to invalid reference")))) - -(defun magit-gh-pulls-url-for-pull (info) - "Return github url for a pull request using INFO." - (let ((url "https://github.com/%s/%s/pull/%s")) - (apply 'format url info))) - -(defun magit-gh-pulls-open-in-browser () - (interactive) - (let ((info (magit-section-value (magit-current-section)))) - (magit-section-case - (pull (browse-url (magit-gh-pulls-url-for-pull info))) - (unfetched-pull (browse-url (magit-gh-pulls-url-for-pull info)))))) - -(defun magit-gh-pulls-purge-cache () - (let* ((api (magit-gh-pulls-get-api)) - (cache (oref api :cache)) - (repo (magit-gh-pulls-guess-repo))) - (pcache-map cache (lambda (k v) - (when (string-match - (format "/repos/%s/%s/" (car repo) (cdr repo)) - (car k)) - (pcache-invalidate cache k)))))) - -(defun magit-gh-pulls-get-remote-default (&optional remote-name-override) - (let ((remote-name (or remote-name-override "origin")) - (remote-branches (magit-git-lines "branch" "-r")) - remote-head) - (while (and remote-branches (not remote-head)) - (let ((m (s-match (format "^\\s-*%s/HEAD -> %s/\\(\\w*\\)" remote-name remote-name) (car remote-branches)))) - (if m - (setq remote-head (cadr m)) - (setq remote-branches (cdr remote-branches))))) - remote-head)) - -(defun magit-gh-pulls-build-req (api user proj callback) - "Builds a request entity for a new pull request. Under - synchronous flow (editor disabled), fires CALLBACK with - API, USER, PROJ and the new REQUEST as args. Under - asynchronous flow, passes all ARGS through to the PR - editor which is responsible for continuing the flow." - (let* ((current (magit-get-current-branch)) - (current-default (magit-gh-pulls-get-remote-default)) - (base-branch (magit-read-branch-or-commit "Base" current-default)) - (head-branch (magit-read-branch-or-commit "Head" current))) - (let* ((head-remote (concat (magit-get-remote base-branch) "/" head-branch)) - (pushed-p (and (magit-branch-p head-remote) - (null (magit-git-lines "diff" (concat head-remote ".." head-branch)))))) - (when (and (not pushed-p) - (yes-or-no-p "PR branch doesn't appear to be pushed. Push it?")) - (magit-push current (magit-get-remote base-branch)))) - (let* ((base - (make-instance 'gh-repos-ref :user (make-instance 'gh-users-user :name user) - :repo (make-instance 'gh-repos-repo :name proj) - :ref base-branch)) - (head - (make-instance 'gh-repos-ref :user (make-instance 'gh-users-user :name user) - :repo (make-instance 'gh-repos-repo :name proj) - :ref head-branch)) - (default-title (magit-git-string "log" - (format "%s..%s" base-branch head-branch) - "--format=%s" "--reverse")) - (default-body (mapconcat 'identity (magit-git-items "log" - (format "%s..%s" base-branch head-branch) - "--reverse" "--format=**%s**%n%b") "\n"))) - - (if (member "--use-pr-editor" (magit-gh-pulls-arguments)) - (magit-gh-pulls-init-pull-editor api user proj default-title default-body base head callback) - (let* ((title (read-string "Title: " default-title)) - (body (read-string "Description: " default-body)) - (req (make-instance 'gh-pulls-request :head head :base base :body body :title title))) - (funcall callback api user proj req)))))) - -(defun magit-gh-pulls-pr-template-file () - "Returns the path to the PULL_REQUEST_TEMPLATE file in the - current repository. Returns nil if there is not a pull request - template file." - (car (directory-files (magit-toplevel) t "^PULL_REQUEST_TEMPLATE"))) - -(defun magit-gh-pulls-init-pull-editor (api user proj default-title default-body base head callback) - "Create a new buffer for editing this pull request and - switch to it. The context needed to finalize the - pull request is stored in a buffer-local var in the - newly created buffer." - (let ((winconf (current-window-configuration)) - (buffer (get-buffer-create (format "*magit-gh-pulls: %s*" proj))) - (context (make-hash-table :test 'equal))) - (dolist (var '(api user proj base head callback)) - (puthash (symbol-name var) (eval var) context)) - (split-window-vertically) - (other-window 1) - (switch-to-buffer buffer) - (funcall 'magit-gh-pulls-editor-mode) - (if (magit-gh-pulls-pr-template-file) - (progn (insert (or default-title "") "\n\n") - (insert-file-contents (magit-gh-pulls-pr-template-file))) - (insert (or default-title "") "\n\n" default-body)) - (goto-char (point-min)) - (message "Opening pull request editor. C-c C-c to finish, C-c C-k to quit.") - (setq-local magit-gh-pulls-editor-context context) - (setq magit-gh-pulls-previous-winconf winconf))) - -(defun magit-gh-pulls-pull-editor-finish () - "Finish editing the current pull request and continue - to submit it. This should be called interactively - from within a pull request editor buffer." - (interactive) - (if (eq nil magit-gh-pulls-editor-context) - (message "This function can only be run in a pull editor buffer.") - (let* ((context magit-gh-pulls-editor-context) - (end-of-first-line (save-excursion - (beginning-of-buffer) - (line-end-position))) - (title (s-trim (buffer-substring-no-properties 1 end-of-first-line))) - (body (s-trim (buffer-substring-no-properties end-of-first-line (point-max)))) - (req (make-instance 'gh-pulls-request - :head (gethash "head" context) - :base (gethash "base" context) - :body body :title title))) - (funcall (gethash "callback" context) - (gethash "api" context) - (gethash "user" context) - (gethash "proj" context) - req) - (magit-gh-pulls-pull-editor-quit)))) - -(defun magit-gh-pulls-pull-editor-quit () - "Cleanup the current pull request editor and restore - the previous window config." - (interactive) - (if (eq nil magit-gh-pulls-editor-context) - (message "This function can only be run in a pull editor buffer.") - (let ((winconf magit-gh-pulls-previous-winconf)) - (kill-buffer) - (kill-local-variable 'magit-gh-pulls-previous-winconf) - (when winconf - (set-window-configuration winconf))))) - -(defun magit-gh-pulls-create-pull-request () - "Entrypoint for creating a new pull request." - (interactive) - (let ((repo (magit-gh-pulls-guess-repo))) - (when repo - (let* ((current-branch (magit-get-current-branch)) - (api (magit-gh-pulls-get-api)) - (user (car repo)) - (proj (cdr repo))) - (magit-gh-pulls-build-req api user proj 'magit-gh-pulls-submit-pull-request))))) - -(defun magit-gh-pulls-submit-pull-request (api user proj req) - "Endpoint for creating a new pull request. Sync and async - flows should both call this function to finish creating - a new pull request." - (interactive) - (let* ((a (gh-pulls-new api user proj req))) - (if (not (= (oref a :http-status) 201)) - (message "Error creating pull-request: %s. Have you pushed the branch to github?" (cdr (assoc "Status" (oref a :headers)))) - (let ((url (oref (oref a :data) :html-url))) - (message (concat "Created pull-request and copied URL to kill ring: " url)) - (when (member "--open-new-in-browser" (magit-gh-pulls-arguments)) - (browse-url url)) - (kill-new url))))) - -(defun magit-gh-pulls-reload () - (interactive) - (let ((creds (magit-gh-pulls-guess-repo))) - (if (not (and creds (car creds) (cdr creds))) - (message "Remote repository is not configured or incorrect.") - (magit-gh-pulls-purge-cache) - (gh-pulls-list (magit-gh-pulls-get-api) (car creds) (cdr creds)) - (magit-refresh)))) - -(easy-menu-define magit-gh-pulls-extension-menu - nil - "GitHub Pull Requests extension menu" - '("GitHub Pull Requests" - :visible magit-gh-pulls-mode - ["Reload pull request" magit-gh-pulls-reload] - ["Create pull request branch" magit-gh-pulls-create-branch] - ["Fetch pull request commits" magit-gh-pulls-fetch-commits] - ["Open pull request in browser" magit-gh-pulls-open-in-browser] - )) - -(easy-menu-add-item 'magit-mode-menu - '("Extensions") - magit-gh-pulls-extension-menu) - -(magit-define-section-jumper magit-jump-to-pulls "Pull Requests" pulls) -(define-key magit-status-mode-map (kbd "jq") 'magit-jump-to-pulls) - -(defvar magit-gh-pulls-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "#") 'magit-gh-pulls-popup) - map)) - -(defvar magit-gh-pulls-mode-lighter " Pulls") - -;;;###autoload -(define-minor-mode magit-gh-pulls-mode "Pull requests support for Magit" - :lighter magit-gh-pulls-mode-lighter - :require 'magit-gh-pulls - :keymap 'magit-gh-pulls-mode-map - (or (derived-mode-p 'magit-mode) - (error "This mode only makes sense with magit")) - (if magit-gh-pulls-mode - (magit-add-section-hook - 'magit-status-sections-hook - 'magit-gh-pulls-insert-gh-pulls - 'magit-insert-stashes) - (remove-hook 'magit-status-sections-hook 'magit-gh-pulls-insert-gh-pulls)) - (when (called-interactively-p 'any) - (magit-refresh))) - -;;;###autoload -(defun turn-on-magit-gh-pulls () - "Unconditionally turn on `magit-pulls-mode'." - (magit-gh-pulls-mode 1)) - -(magit-define-popup magit-gh-pulls-popup - "Show popup buffer featuring Github Pull Requests commands." - 'magit-commands - :switches '((?c "Produce merge commit" "--no-ff") - (?w "Open new PR in browser" "--open-new-in-browser") - (?e "Edit PR in full buffer" "--use-pr-editor")) - :actions '((?g "Reload" magit-gh-pulls-reload) - (?f "Fetch" magit-gh-pulls-fetch-commits) - (?d "Diff" magit-gh-pulls-diff-pull-request) - (?b "Make branch" magit-gh-pulls-create-branch) - (?m "Merge" magit-gh-pulls-merge-pull-request) - (?c "Create new PR" magit-gh-pulls-create-pull-request) - (?o "Open in browser" magit-gh-pulls-open-in-browser)) - :default-action 'magit-gh-pulls-reload) - -(provide 'magit-gh-pulls) -;; Local Variables: -;; indent-tabs-mode: nil -;; End: -;;; magit-gh-pulls.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-autoloads.el b/elpa/magithub-20160926.2044/magithub-autoloads.el new file mode 100644 index 0000000..46b11bc --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-autoloads.el @@ -0,0 +1,17 @@ +;;; magithub-autoloads.el --- automatically extracted autoloads +;; +;;; Code: +(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path)))) + +;;;### (autoloads nil nil ("magithub-cache.el" "magithub-ci.el" "magithub-core.el" +;;;;;; "magithub-issue.el" "magithub-pkg.el" "magithub.el") (22506 +;;;;;; 26931 120335 726000)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; End: +;;; magithub-autoloads.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-cache.el b/elpa/magithub-20160926.2044/magithub-cache.el new file mode 100644 index 0000000..7a872f5 --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-cache.el @@ -0,0 +1,67 @@ +;;; magithub-cache.el --- caching network data -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sean Allred + +;; Author: Sean Allred +;; Keywords: data, tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(defvar magithub-cache--cache (make-hash-table) + "A hash table to use as a cache. +Entries are of the form (time-entered . value).") + +(defvar magithub-cache-refresh-seconds-plist + (list :issues 600 :ci-status 60) + "The number of seconds that have to pass for GitHub data to be +considered outdated.") + +(defun magithub-cache (cache default) + "The cached value for CACHE (set to DEFAULT if necessary)." + (declare (indent defun)) + (let ((cached-value (gethash cache magithub-cache--cache :no-value))) + (if (or (eq cached-value :no-value) + (< (plist-get magithub-cache-refresh-seconds-plist cache) + (time-to-seconds (time-since (car cached-value))))) + (cdr (puthash cache (cons (current-time) (eval default)) + magithub-cache--cache)) + (when magithub-debug-mode + (message "Using cached value for %S (retrieved %s)" + cache (format-time-string "%F %T" (car cached-value)))) + (cdr cached-value)))) + +(defun magithub-cache-value (cache) + "The cached value for CACHE." + (let ((c (gethash cache magithub-cache--cache :no-value))) + (unless (eq c :no-value) + (cdr c)))) + +(defun magithub-cache-clear (cache) + "Clear the cache." + (remhash cache magithub-cache--cache)) + +(defun magithub-refresh () + "Refresh all GitHub data." + (interactive) + (setq magithub-cache--cache (make-hash-table)) + (magit-refresh)) + +(provide 'magithub-cache) +;;; magithub-cache.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-ci.el b/elpa/magithub-20160926.2044/magithub-ci.el new file mode 100644 index 0000000..4ed6b8e --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-ci.el @@ -0,0 +1,197 @@ +;;; magithub-ci.el --- Show CI status as a magit-status header -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sean Allred + +;; Author: Sean Allred +;; Keywords: tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Provide the CI status of "origin" in the Magit status buffer. + +;;; Code: + +(require 'magit) +(require 'magit-section) +(require 'magit-popup) + +(require 'magithub-core) +(require 'magithub-cache) + +(defun magithub-maybe-insert-ci-status-header () + "If this is a GitHub repository, insert the CI status header." + (when (and (magithub-github-repository-p) + (executable-find magithub-hub-executable)) + (magithub-insert-ci-status-header))) + +(defun magithub-ci-status () + "One of 'success, 'error, 'failure, 'pending, or 'no-status." + (let ((same-commit + (string-equal (magit-rev-parse "HEAD") + (magithub-ci-status-current-commit)))) + (unless same-commit + (magithub-cache-clear :ci-status)) + (if (eq (magithub-cache-value :ci-status) 'success) + 'success + (magithub-cache :ci-status + '(magithub-ci-status--internal))))) + +(defun magithub-ci-status-current-commit (&optional new-value) + "The commit our cached value corresponds to." + (let ((keys (list "magithub" "ci" "lastCommit"))) + (if new-value (apply #'magit-set new-value keys) + (apply #'magit-get keys)))) + +(defun magithub-ci-status--internal (&optional ignore-ci-skips) + "One of 'success, 'error, 'failure, 'pending, or 'no-status." + (with-temp-message "Updating CI status..." + (let* ((last-commit (when ignore-ci-skips (magithub-ci-status--last-commit))) + (output (car (magithub--command-output "ci-status" last-commit)))) + (if output + (let* ((output (replace-regexp-in-string "\s" "-" output)) + (status (intern output))) + (if (and (not ignore-ci-skips) (eq status 'no-status)) + (magithub-ci-status--internal t) + (magithub-ci-status-current-commit (magit-rev-parse "HEAD")) + status)) + (beep) + (setq magithub-hub-error + (message + (concat "Hub didn't have any output for \"ci-status\"!\n" + "Consider submitting an issue to github/hub."))) + 'internal-error)))) + +(defun magithub-ci-status--last-commit () + "Find the commit considered to have the current CI status. +Right now, this finds the most recent commit without + + [ci skip] + +or + + [skip ci] + +in the commit message. + +See the following resources: + + - https://docs.travis-ci.com/user/customizing-the-build#Skipping-a-build + - https://circleci.com/docs/skip-a-build/" + (let* ((args '("--invert-grep" + "--grep=\\[ci skip\\]" + "--grep=\\[skip ci\\]" + "--format=oneline" + "--max-count=1")) + (output (magit-git-lines "log" args))) + (car (split-string (car output))))) + +(defvar magithub-ci-status-alist + '((no-status . "None") + (error . "Error") + (internal-error . magithub-ci--hub-error-string) + (failure . "Failure") + (pending . "Pending") + (success . "Success"))) + +(defun magithub-ci--hub-error-string () + "Internal error string." + (format "Internal error!\n%s" magithub-hub-error)) + +(defface magithub-ci-no-status + '((((class color)) :inherit magit-dimmed)) + "Face used when CI status is `no-status'." + :group 'magithub-faces) + +(defface magithub-ci-error + '((((class color)) :inherit magit-signature-untrusted)) + "Face used when CI status is `error'." + :group 'magithub-faces) + +(defface magithub-ci-pending + '((((class color)) :inherit magit-signature-untrusted)) + "Face used when CI status is `pending'." + :group 'magithub-faces) + +(defface magithub-ci-success + '((((class color)) :inherit magit-signature-good)) + "Face used when CI status is `success'." + :group 'magithub-faces) + +(defface magithub-ci-failure + '((((class color)) :inherit magit-signature-bad)) + "Face used when CI status is `'" + :group 'magithub-faces) + +(defface magithub-ci-unknown + '((((class color)) :inherit magit-signature-untrusted)) + "Face used when CI status is `unknown'." + :group 'magithub-faces) + +(defun magithub-ci-visit () + "Browse the CI. +Sets up magithub.ci.url if necessary." + (interactive) + (let ((var-value (magit-get "magithub" "ci" "url"))) + (unless var-value + (magit-set + (setq var-value (read-from-minibuffer "I don't know the CI URL yet -- what is it? I'll remember: ") + var-value (if (string-equal "" var-value) nil var-value)) + "magithub" "ci" "url")) + (browse-url var-value))) + +(defvar magit-magithub-ci-status-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] #'magithub-ci-visit) + (define-key map [remap magit-refresh] #'magithub-ci-refresh) + map) + "Keymap for `magithub-ci-status' header section.") + +(defun magithub-ci-refresh () + "Invalidate the CI cache and refresh the buffer." + (interactive) + (magithub-cache-clear :ci-status) + (when (derived-mode-p 'magit-status-mode) + (magit-refresh))) + +(defun magithub-insert-ci-status-header () + (let* ((status (magithub-ci-status)) + (face (intern (format "magithub-ci-%s" + (symbol-name status)))) + (status-val (cdr (assq status magithub-ci-status-alist)))) + (magit-insert-section (magithub-ci-status) + (insert (format "%-10s" "CI: ")) + (insert (propertize + (cond + ((stringp status-val) status-val) + ((functionp status-val) (funcall status-val)) + (t (format "%S" status-val))) + 'face (if (facep face) face 'magithub-ci-unknown))) + (insert ?\n)))) + +(defun magithub-toggle-ci-status-header () + (interactive) + (if (memq #'magithub-maybe-insert-ci-status-header magit-status-headers-hook) + (remove-hook 'magit-status-headers-hook #'magithub-maybe-insert-ci-status-header) + (if (executable-find magithub-hub-executable) + (add-hook 'magit-status-headers-hook #'magithub-maybe-insert-ci-status-header t) + (message "Magithub: (magithub-toggle-ci-status-header) `hub' isn't installed, so I can't insert the CI header"))) + (when (derived-mode-p 'magit-status-mode) + (magit-refresh))) + +(magithub-toggle-ci-status-header) + +(provide 'magithub-ci) +;;; magithub-ci.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-core.el b/elpa/magithub-20160926.2044/magithub-core.el new file mode 100644 index 0000000..af2124f --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-core.el @@ -0,0 +1,149 @@ +;;; magithub-core.el --- core functions for magithub -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sean Allred + +;; Author: Sean Allred +;; Keywords: tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(require 'magit) + +(defun magithub-github-repository-p () + "Non-nil if \"origin\" points to GitHub." + (let ((url (magit-get "remote" "origin" "url"))) + (or (s-prefix? "git@github.com:" url) + (s-prefix? "https://github.com/" url) + (s-prefix? "git://github.com/" url)))) + +(defun magithub--api-available-p () + "Non-nil if the API is available." + (let ((magit-git-executable "ping") + (magit-pre-call-git-hook nil) + (magit-git-global-arguments nil)) + (= 0 (magit-git-exit-code "-c 1" "api.github.com")))) + +(defun magithub--completing-read-multiple (prompt collection) + "Using PROMPT, get a list of elements in COLLECTION. +This function continues until all candidates have been entered or +until the user enters a value of \"\". Duplicate entries are not +allowed." + (let (label-list this-label done) + (while (not done) + (setq collection (remove this-label collection) + this-label "") + (when collection + ;; @todo it would be nice to detect whether or not we are + ;; allowed to create labels -- if not, we can require-match + (setq this-label (completing-read prompt collection))) + (unless (setq done (s-blank? this-label)) + (push this-label label-list))) + label-list)) + +(defconst magithub-hash-regexp + (rx bow (= 40 (| digit (any (?A . ?F) (?a . ?f)))) eow) + "Regexp for matching commit hashes.") + +(defcustom magithub-hub-executable "hub" + "The hub executable used by Magithub." + :group 'magithub + :package-version '(magithub . "0.1") + :type 'string) + +(defvar magithub-debug-mode nil + "When non-nil, echo hub commands before they're executed.") + +(defvar magithub-hub-error nil + "When non-nil, this is a message for when hub fails.") + +(defmacro magithub-with-hub (&rest body) + `(let ((magit-git-executable magithub-hub-executable) + (magit-pre-call-git-hook nil) + (magit-git-global-arguments nil)) + ,@body)) + +(defun magithub--hub-command (magit-function command args) + (unless (executable-find magithub-hub-executable) + (user-error "Hub (hub.github.com) not installed; aborting")) + (unless (file-exists-p "~/.config/hub") + (user-error "Hub hasn't been initialized yet; aborting")) + (when magithub-debug-mode + (message "Calling hub with args: %S %S" command args)) + (with-timeout (5 (error "Took too long! %s%S" command args)) + (magithub-with-hub (funcall magit-function command args)))) + +(defun magithub--command (command &optional args) + "Run COMMAND synchronously using `magithub-hub-executable'." + (magithub--hub-command #'magit-run-git command args)) + +(defun magithub--command-with-editor (command &optional args) + "Run COMMAND asynchronously using `magithub-hub-executable'. +Ensure GIT_EDITOR is set up appropriately." + (magithub--hub-command #'magit-run-git-with-editor command args)) + +(defun magithub--command-output (command &optional args) + "Run COMMAND synchronously using `magithub-hub-executable' +and returns its output as a list of lines." + (magithub--hub-command #'magit-git-lines command args)) + +(defun magithub--command-quick (command &optional args) + "Quickly execute COMMAND with ARGS." + (ignore (magithub--command-output command args))) + +(defun magithub--meta-new-issue () + "Open a new Magithub issue. +See /.github/ISSUE_TEMPLATE.md in this repository." + (interactive) + (browse-url "https://github.com/vermiculus/magithub/issues/new")) + +(defun magithub--meta-help () + "Opens Magithub help." + (interactive) + (browse-url "https://gitter.im/vermiculus/magithub")) + +(defun magithub-error (err-message tag &optional trace) + "Report a Magithub error." + (setq trace (or trace (with-output-to-string (backtrace)))) + (when (y-or-n-p (concat tag " Report? (A bug report will be placed in your clipboard.)")) + (with-current-buffer-window + (get-buffer-create "*magithub issue*") + #'display-buffer-pop-up-window nil + (when (fboundp 'markdown-mode) (markdown-mode)) + (insert + (kill-new + (format + "## Automated error report + +### Description + +%s + +### Backtrace + +``` +%s``` +" + (read-string "Briefly describe what you were doing: ") + trace)))) + (magithub--meta-new-issue)) + (error err-message)) + +(provide 'magithub-core) +;;; magithub-core.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-issue.el b/elpa/magithub-20160926.2044/magithub-issue.el new file mode 100644 index 0000000..a95e94a --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-issue.el @@ -0,0 +1,179 @@ +;;; magithub-issue.el --- Browse issues with Magithub -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sean Allred + +;; Author: Sean Allred +;; Keywords: tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Jump to issues from `magit-status'! + +;;; Code: + +(require 'magit) +(require 'magit-section) + +(require 'magithub-core) +(require 'magithub-cache) + +(magit-define-popup magithub-issues-popup + "Popup console for creating GitHub issues." + 'magithub-commands + :man-page "hub" + :options '((?l "Add labels" "--label=" magithub-issue-read-labels)) + :actions '((?c "Create new issue" magithub-issue-new))) + +(defvar magithub-issue-format + (list :number " %3d " + :title " %s ") + "These properties will be inserted in the order in which their +found. See `magithub-issue--process-line'.") + +(defun magithub-issue-new () + "Create a new issue on GitHub." + (interactive) + (unless (magithub-github-repository-p) + (user-error "Not a GitHub repository")) + (magithub--command-with-editor + "issue" (cons "create" (magithub-issues-arguments)))) + +(defun magithub-issue-label-list () + "Return a list of issue labels. +This is a hard-coded list right now." + (list "bug" "duplicate" "enhancement" + "help wanted" "invalid" "question" "wontfix")) + +(defun magithub-issue-read-labels (prompt &optional default) + "Read some issue labels and return a comma-separated string. +Available issues are provided by `magithub-issue-label-list'. + +DEFAULT is a comma-separated list of issues -- those issues that +are in DEFAULT are not prompted for again." + ;; todo: probably need to add DEFAULT to the top here + (s-join + "," + (magithub--completing-read-multiple + (format "%s... %s" prompt "Issue labels (or \"\" to quit): ") + (let* ((default-labels (when default (s-split "," default t)))) + (cl-set-difference (magithub-issue-label-list) default-labels))))) + +(defun magithub-issue--process-line (s) + "Process a line S into an issue. + +Returns a plist with the following properties: + + :number issue or pull request number + :type either 'pull-request or 'issue + :title the title of the issue or pull request + :url link to issue or pull request" + (let (number title url) + (if (ignore-errors + (with-temp-buffer + (insert s) + (goto-char 0) + (search-forward "]") + (setq number (string-to-number (substring s 0 (point)))) + (setq title (substring s (point) + (save-excursion + (goto-char (point-max)) + (- (search-backward "(") 2)))) + (goto-char (point-max)) + (delete-char -2) + (search-backward "(") + (forward-char 2) + (setq url (buffer-substring-no-properties (point) (point-max))) + t)) + (list :number number + :type (if (string-match-p (rx "/pull/" (+ digit) eos) url) + 'pull-request 'issue) + :title title + :url url) + (magithub-error + "failed to parse issue" + "There was an error parsing issues.")))) + +(defun magithub-issue-list () + "Return a list of issues for the current repository." + (magithub-cache :issues + '(with-temp-message "Retrieving issue list..." + (magithub-issue-list--internal)))) + +(defun magithub-issue-list--internal () + (sort (mapcar #'magithub-issue--process-line + (magithub--command-output "issue")) + (lambda (a b) (< (plist-get a :number) + (plist-get b :number))))) + +(defun magithub-issue--insert (issue) + "Insert an `issue' as a Magit section into the buffer." + (when issue + (magit-insert-section (magithub-issue issue) + (let ((formats (or magithub-issue-format + (list :number " %3d " :title " %s ")))) + (while formats + (let ((key (car formats)) (fmt (cadr formats))) + (insert (format fmt (plist-get issue key)))) + (setq formats (cddr formats)))) + (insert ?\n)))) + +(defun magithub-issue-browse (issue) + "Visits `issue' in the browser. +Interactively, this finds the issue at point. + +If `issue' is nil, open the repository's issues page." + (interactive (list (magit-section-value + (magit-current-section)))) + (browse-url + (if (plist-member issue :url) + (plist-get issue :url) + (car (magithub--command-output "browse" '("--url-only" "--" "issues")))))) + +(defun magithub-issue-refresh () + (interactive) + (magithub-cache-clear :issues) + (when (derived-mode-p 'magit-status-mode) + (magit-refresh))) + +(defvar magit-magithub-issue-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] #'magithub-issue-browse) + (define-key map [remap magit-refresh] #'magithub-issue-refresh) + map) + "Keymap for `magithub-issue' sections.") + +(defvar magit-magithub-issue-list-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] #'magithub-issue-browse) + (define-key map [remap magit-refresh] #'magithub-issue-refresh) + map) + "Keymap for `magithub-issue-list' sections.") + +(defun magithub-issue--insert-section () + "Insert GitHub issues if appropriate." + (when (and (magithub-github-repository-p) + (executable-find magithub-hub-executable)) + (let* ((issues (magithub-issue-list))) + (magit-insert-section (magithub-issue-list) + (magit-insert-heading "Issues and Pull Requests") + (if issues (mapc #'magithub-issue--insert issues) + (insert " No issues.\n")))))) + +;;; Hook into the status buffer +(add-hook 'magit-status-sections-hook #'magithub-issue--insert-section t) + +(provide 'magithub-issue) +;;; magithub-issue.el ends here diff --git a/elpa/magithub-20160926.2044/magithub-pkg.el b/elpa/magithub-20160926.2044/magithub-pkg.el new file mode 100644 index 0000000..6bf3c59 --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub-pkg.el @@ -0,0 +1,12 @@ +(define-package "magithub" "20160926.2044" "Magit interfaces for GitHub" + '((emacs "24.3") + (magit "2.8.0") + (git-commit "20160821.1338") + (with-editor "20160828.1025") + (cl-lib "1.0") + (s "20160711.525")) + :url "https://github.com/vermiculus/magithub" :keywords + '("git" "tools" "vc")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/magithub-20160926.2044/magithub.el b/elpa/magithub-20160926.2044/magithub.el new file mode 100644 index 0000000..665b5a5 --- /dev/null +++ b/elpa/magithub-20160926.2044/magithub.el @@ -0,0 +1,207 @@ +;;; magithub.el --- Magit interfaces for GitHub -*- lexical-binding: t; -*- + +;; Copyright (C) 2016 Sean Allred + +;; Author: Sean Allred +;; Keywords: git, tools, vc +;; Homepage: https://github.com/vermiculus/magithub +;; Package-Requires: ((emacs "24.3") (magit "2.8.0") (git-commit "20160821.1338") (with-editor "20160828.1025") (cl-lib "1.0") (s "20160711.525")) +;; Package-Version: 0.1 + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Magithub is an interface to GitHub using the `hub' utility [1]. +;; +;; Integrated into Magit workflows, Magithub allows very easy, very +;; basic GitHub repository management. Supported actions include: +;; +;; - pushing brand-new local repositories up to GitHub +;; - creating forks of existing repositories +;; - submitting pull requests upstream +;; - viewing and creating issues +;; +;; Press `H' in the status buffer to get started -- happy hacking! +;; +;; [1]: https://hub.github.com + +;; Requires hub 2.2.8 + +;;; Code: + +(require 'magit) +(require 'magit-process) +(require 'magit-popup) +(require 'git-commit) +(require 'with-editor) +(require 'cl-lib) +(require 's) + +(require 'magithub-core) +(require 'magithub-issue) +(require 'magithub-cache) +(require 'magithub-ci) + +(magit-define-popup magithub-dispatch-popup + "Popup console for dispatching other Magithub popups." + 'magithub-commands + :man-page "hub" + :actions '("Actions" + (?H "Browse on GitHub" magithub-browse) + (?c "Create" magithub-create-popup) + (?f "Fork" magithub-fork-popup) + (?i "Issues" magithub-issues-popup) + (?p "Submit a pull request" magithub-pull-request-popup) + "Meta" + (?g "Refresh all GitHub data" magithub-refresh) + (?& "Request a feature or report a bug" magithub--meta-new-issue) + (?h "Ask for help on Gitter" magithub--meta-help))) + +(magit-define-popup-action 'magit-dispatch-popup + ?H "Magithub" #'magithub-dispatch-popup ?!) +(define-key magit-status-mode-map + "H" #'magithub-dispatch-popup) + +(magit-define-popup magithub-create-popup + "Popup console for creating GitHub repositories." + 'magithub-commands + :man-page "hub" + :switches '((?p "Mark as private" "-p")) + :actions '((?c "Create this repository" magithub-create)) + :options '((?d "Description" "--description=") + (?h "Homepage" "--homepage="))) + +(magit-define-popup magithub-fork-popup + "Popup console for forking GitHub repositories." + 'magithub-commands + :man-page "hub" + :switches '((?r "Don't add my fork as a remote in this repository" "--no-remote")) + :actions '((?f "Fork the project at origin" magithub-fork))) + +(magit-define-popup magithub-pull-request-popup + "Popup console for creating pull requests on GitHub repositories." + 'magithub-commands + :man-page "hub" + :switches '((?f "Ignore unpushed commits" "-f") + (?o "Open in my browser" "-o")) + :options '((?b "Base branch" "--base=" magit-read-branch) + (?h "Head branch" "--head=" magit-read-branch)) + :actions '((?P "Submit a pull request" magithub-pull-request)) + :default-arguments '("-o")) + +(defun magithub-browse () + "Open the repository in your browser." + (interactive) + (unless (magithub-github-repository-p) + (user-error "Not a GitHub repository")) + (magithub--command-quick "browse")) + +(defvar magithub-after-create-messages + '("Don't be shy!" + "Don't let your dreams be dreams!") + "One of these messages will be displayed after you create a +GitHub repository.") + +(defun magithub-create () + "Create the current repository on GitHub." + (interactive) + (message "Creating repository on GitHub...") + (magithub--command "create" (magithub-create-arguments)) + (message "Creating repository on GitHub...done! %s" + (nth (random (length magithub-after-create-messages)) + magithub-after-create-messages)) + (magit-push-popup)) + +(defun magithub-fork () + "Fork 'origin' on GitHub." + (interactive) + (unless (magithub-github-repository-p) + (user-error "Not a GitHub repository")) + (when (and (s-equals? "master" (magit-get-current-branch)) + (y-or-n-p "Looks like master is checked out. Create a new branch? ")) + (call-interactively #'magit-branch-spinoff)) + (message "Forking repository on GitHub...") + (magithub--command "fork" (magithub-fork-arguments)) + (message "Forking repository on GitHub...done")) + +(defun magithub-pull-request () + "Open a pull request to 'origin' on GitHub." + (interactive) + (unless (magithub-github-repository-p) + (user-error "Not a GitHub repository")) + (let (just-pushed) + (unless (magit-get-push-remote) + (when (y-or-n-p "No push remote defined; push now? ") + (call-interactively #'magit-push-current-to-pushremote) + (setq just-pushed t))) + (unless (magit-get-push-remote) + (user-error "No push remote defined; aborting pull request")) + (unless just-pushed + (when (y-or-n-p "Do you want to push any more commits? ") + (magit-push-popup))) + (magithub--command-with-editor "pull-request" (magithub-pull-request-arguments)))) + +(defface magithub-issue-warning-face + '((((class color)) :foreground "red")) + "Face used to call out warnings in the issue-create buffer." + :group 'magithub) + +(defun magithub-setup-edit-buffer () + "Perform setup on a hub edit buffer." + (with-editor-mode 1) + (git-commit-setup-font-lock) + (font-lock-add-keywords + nil `((,magithub-hash-regexp (0 'magit-hash t))) t) + (add-hook + (make-local-variable 'with-editor-pre-finish-hook) + (lambda () + (let ((fill-column (point-max))) + (fill-region (point-min) (point-max)))))) + +(defun magithub-setup-new-issue-buffer () + "Setup the buffer created for issue-posting." + (font-lock-add-keywords + nil '(("^# \\(Creating issue for .*\\)" (1 'magithub-issue-warning-face t))) t)) + +(defvar magithub--file-types + '(("ISSUE_EDITMSG" . issue) + ("PULLREQ_EDITMSG" . pull-request)) + "File types -- car is the basename of a file in /.git/, cdr is + one of `issue' or `pull-request'.") + +(defun magithub--edit-file-type (path) + "Determine the type of buffer this is (if it was created by hub). +Returns `issue', `pull-request', or another non-nil value if +created by hub. + +This function will return nil for matches to +`git-commit-filename-regexp'." + (let ((basename (file-name-base path))) + (and path + (s-suffix? "/.git/" (file-name-directory path)) + (not (s-matches? git-commit-filename-regexp basename)) + (cdr (assoc basename magithub--file-types))))) + +(defun magithub-check-buffer () + "If this is a buffer created by hub, perform setup." + (let ((type (magithub--edit-file-type buffer-file-name))) + (when type + (magithub-setup-edit-buffer) + (when (eq type 'issue) + (magithub-setup-new-issue-buffer))))) +(add-hook 'find-file-hook #'magithub-check-buffer) + +(provide 'magithub) +;;; magithub.el ends here