;;; my-github.el -- Github client -*- lexical-binding: t -*- ;; Copyright (C) 2023 Free Software Foundation. ;; Author: Yuchen Pei ;; Package-Requires: ((emacs "28.2")) ;; This file is part of dotfiles. ;; dotfiles is free software: you can redistribute it and/or modify it under ;; the terms of the GNU Affero General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; dotfiles 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 Affero General ;; Public License for more details. ;; You should have received a copy of the GNU Affero General Public ;; License along with dotfiles. If not, see . ;;; Commentary: ;; Github client. ;;; Code: (defun my-grok-github (url) "get github info of a project. url is the url of the project License; name; description; homepage; created at" (when (string-match "github.com\\(/[^/]+/[^/]+\\)/?.*$" url) (with-current-buffer (url-retrieve-synchronously (concat "https://api.github.com/repos" (replace-regexp-in-string "\\.git$" "" (match-string 1 url)))) (set-buffer-multibyte t) (my-delete-http-header) (my-grok-github-make-info (json-read))))) (defun my-post-process-licensing-name (name) (cond ((equal name "MIT") "expat") (t name))) (defun my-grok-github-make-info (raw) (list (cons "Title" (alist-get 'name raw)) (cons "Description" (alist-get 'description raw)) (cons "Source" (alist-get 'html_url raw)) (cons "Website" (alist-get 'homepage raw)) (cons "Released" (substring (alist-get 'created_at raw) 0 10)) (cons "Pushed" (substring (alist-get 'pushed_at raw) 0 10)) (cons "Subject" (string-join (alist-get 'topics raw) ", ")) ;; FIXME: why did we comment this out? ;; (cons "License" (my-post-process-licensing-name ;; (alist-get 'spdx_id (alist-get 'license raw)))) (cons "Developers" (my-grok-github-get-developer-name (alist-get 'url (alist-get 'owner raw)))))) (defun my-grok-github-get-developer-name (url) (with-current-buffer (url-retrieve-synchronously url) (set-buffer-multibyte t) (my-delete-http-header) (alist-get 'name (json-read)))) ;;; urls with github ;; TODO: generalise the following to common forges, including ;; savannah, cgit, gitlab etc. (defun my-github-revision-url (file revision) "Returns the github url of the upstream repo containing FILE at REVISION." (let ((repo-url (vc-git-repository-url file)) (revision (or revision (vc-working-revision default-directory)))) (format "%s/commit/%s" repo-url revision))) (defun my-github-kill-revision-url (revision) "Kill the github revision url for REVISION." (kill-new (my-github-revision-url revision))) (defun my-github-file-loc-url (file-loc &optional revision) "Convert a file location to a github url." (pcase-let* ((`(,file ,line-no) (split-string file-loc ":")) (revision (or revision (vc-working-revision file)))) (my-github-file-loc-url-internal file line-no revision))) (defun my-github-file-loc-url-internal (file line-no revision) "Convert a FILE location at LINE-NO to a github url. REVISION is the commit hash." (let* ((repo-url (vc-git-repository-url file)) (repo-root (vc-git-root file)) (path (file-relative-name file repo-root))) (format "%s/blob/%s/%s#L%s" repo-url revision path line-no))) (defun my-github-kill-current-file-loc-url () "Kill the github url from where the point is at." (interactive) (kill-new (my-github-file-loc-url-internal (buffer-file-name) (1+ (current-line)) (vc-working-revision (buffer-file-name))))) (defun my-org-backtrace-to-github (bt &optional revision) (string-join (mapcar (lambda (link) (string-match "\\[\\[\\(.*\\)\\]\\[\\(.*\\)\\]\\]" link) (let ((target (match-string 1 link)) (label (match-string 2 link))) (format "[[%s][%s]]" (my-github-file-loc-url target revision) label))) (split-string bt " > ")) " > ")) (defun my-org-backtrace-to-github-region (beg end) (interactive "r") (kill-new (my-org-backtrace-to-github (buffer-substring-no-properties beg end)))) (defun my-org-backtrace-to-github-slack (beg end) (interactive "r") (let ((bt (buffer-substring-no-properties beg end)) (revision (when current-prefix-arg (read-string "Rrevision: "))) ) (with-temp-buffer (insert "#+options: ^:nil ") (goto-char (point-max)) (insert (my-org-backtrace-to-github bt revision)) (org-md-export-as-markdown)))) (provide 'my-github) ;;; my-github.el ends here