blob: 72110b05c90071a56b1e60523096eba91bc1aad7 [file] [log] [blame]
;; -*- lexical-binding: t -*-
;; Copyright 2020 The Chromium OS Authors. All Rights Reserved.
;; Use of this source code is governed by a BSD-style license that can be
;; found in the LICENSE file.
;; repo-transient.el --- Transient menus to use some repo commands within magit
;;
;; This file is not part of GNU Emacs.
(require 'transient)
(require 'magit-process)
(define-infix-argument repo:current-project ()
:description "Current Project"
:class 'transient-switch
:key "-c"
:argument ".")
(define-infix-argument repo:all-projects ()
:description "All Projects"
:class 'transient-switch
:key "-A"
:argument "--all")
(defun repo-sync (args)
"Run a repo sync command."
(interactive (list (transient-args 'repo-sync-menu)))
(apply #'magit-call-process "repo" "sync" args)
(magit-refresh-all))
(defun repo-rebase (args)
"Run a repo rebase command."
(interactive (list (transient-args 'repo-rebase-menu)))
(apply #'magit-call-process "repo" "rebase" args)
(magit-refresh-all))
(define-transient-command repo-sync-menu ()
"Transient menu for repo sync."
["Project"
(repo:current-project)]
["Commands"
("y" "Sync" repo-sync)])
(define-transient-command repo-rebase-menu
"Transient menu for repo rebase."
["Project"
(repo:current-project)]
["Commands"
("r" "Rebase" repo-rebase)])
(defun repo-prune ()
"Run a repo prune command."
(interactive)
(magit-call-process "repo" "--no-pager" "prune" "-q")
(magit-refresh-all))
(defvar repo--branch-name-history '())
(defun repo--start (branch-name &optional args)
"Run a repo start command."
(apply #'magit-call-process "repo" "start" `(,@args ,branch-name))
(magit-refresh-all))
(defun repo-start (args)
(interactive (list (transient-args 'repo-start-menu)))
(let ((branch-name
(magit-read-string-ns "Branch name" nil 'repo--branch-name-history)))
(when branch-name
(repo--start branch-name args)
(add-to-history 'repo--branch-name-history branch-name))))
(defun repo-start-temp (args)
"Run a repo start command with an auto-generated branch name."
(interactive (list (transient-args 'repo-start-menu)))
(repo--start (format-time-string "temp-%Y-%m-%dT%H-%M-%S")
args))
(define-transient-command repo-start-menu ()
"Transient menu for repo start."
["Project"
(repo:all-projects)]
["Revision"
("-h" "Start at HEAD" "--head")]
["Commands"
("s" "Start new development branch" repo-start)
("t" "Start temporary development branch" repo-start-temp)])
(defun repo-upload (args)
"Run a repo upload command."
(cond
((and (not (member "--label=Verified+1" args))
(not (member "--label=Verified-1" args)))
(repo-upload `(,@args "--label=Verified+1")))
((and (not (member "--cbr" args))
(not (seq-some (lambda (arg)
(string-prefix-p "--br=" arg))
args)))
(repo-upload `(,@args "--cbr")))
;; --no-verify is safe, as we ran the repohooks just before in
;; repo-upload-menu-with-repohooks.
(t (apply #'magit-call-process "repo" "upload" "--yes" "--no-verify" args)
(magit-refresh-all))))
(defun repo-upload-current (args)
"Run a repo upload command in the current project."
(interactive (list (transient-args 'repo-upload-menu)))
(repo-upload (cons "." args)))
(defun repo-upload-all (args)
"Run a repo upload command for all projects."
(interactive (list (transient-args 'repo-upload-menu)))
(repo-upload args))
(define-infix-argument repo:--re ()
:description "Set reviewers"
:class 'transient-option
:key "-r"
:argument "--re=")
(define-infix-argument repo:--cc ()
:description "Set reviewers"
:class 'transient-option
:key "-c"
:argument "--cc=")
(define-infix-argument repo:--br ()
:description "Local branch to upload"
:class 'transient-option
:key "-b"
:argument "--br="
:reader 'magit-transient-read-revision)
(define-infix-argument repo:--dest ()
:description "Remote destination branch"
:class 'transient-option
:key "-D"
:argument "--dest=")
(define-infix-argument repo:--hashtag ()
:description "Hashtags"
:class 'transient-option
:key "-h"
:argument "--hashtag=")
(define-transient-command repo-upload-menu ()
"Transient menu for repo upload."
["People"
(repo:--re)
(repo:--cc)
("-E" "Don't send emails" "--no-emails")]
["Labels"
("-a" "Label Auto-Submit+1" "--label=Auto-Submit+1")
("-d" "Label Commit-Queue+1 (dry run)" "--label=Commit-Queue+1")
("-Q" "Label Commit-Queue+2" "--label=Commit-Queue+2")
("-B" "Label Verified-1 (BAD)" "--label=Verified-1")]
["CL Options"
("-w" "Work in Progress" "--wip")
("-p" "Private" "--private")
(repo:--hashtag)]
["Branches"
(repo:--br)
(repo:--dest)]
["Upload"
("u" "Upload current project" repo-upload-current)
("U" "Upload all projects" repo-upload-all)])
(defun repo-upload-menu-with-repohooks ()
"Run repohooks before showing the repo upload menu"
(interactive)
(message "Running repohooks...")
(let ((magit-process-raise-error t)
(do-upload t))
(condition-case nil
(magit-call-process "repo" "upload" "." "--cbr" "--yes" "--dry-run")
('magit-git-error (magit-process-buffer)
(unless (magit-y-or-n-p "Repohooks failed. Continue?")
(setq do-upload nil))))
(when do-upload
(repo-upload-menu))))
(define-transient-command repo-main-menu ()
"Transient menu for repo commands."
["Subcommands"
("y" "sync" repo-sync-menu)
("r" "rebase" repo-rebase-menu)
("p" "prune" repo-prune)
("s" "start" repo-start-menu)
("u" "upload" repo-upload-menu-with-repohooks)
("U" "upload, no repohooks" repo-upload-menu)])
(provide 'repo-transient)