dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

magit-tag.el (8445B)


      1 ;;; magit-tag.el --- tag functionality  -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2010-2021  The Magit Project Contributors
      4 ;;
      5 ;; You should have received a copy of the AUTHORS.md file which
      6 ;; lists all contributors.  If not, see http://magit.vc/authors.
      7 
      8 ;; Author: Jonas Bernoulli <jonas@bernoul.li>
      9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
     10 
     11 ;; SPDX-License-Identifier: GPL-3.0-or-later
     12 
     13 ;; Magit is free software; you can redistribute it and/or modify it
     14 ;; under the terms of the GNU General Public License as published by
     15 ;; the Free Software Foundation; either version 3, or (at your option)
     16 ;; any later version.
     17 ;;
     18 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
     19 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     20 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     21 ;; License for more details.
     22 ;;
     23 ;; You should have received a copy of the GNU General Public License
     24 ;; along with Magit.  If not, see http://www.gnu.org/licenses.
     25 
     26 ;;; Commentary:
     27 
     28 ;; This library implements tag commands.
     29 
     30 ;;; Code:
     31 
     32 (require 'magit)
     33 
     34 ;; For `magit-tag-delete'.
     35 (defvar helm-comp-read-use-marked)
     36 
     37 ;;;###autoload (autoload 'magit-tag "magit" nil t)
     38 (transient-define-prefix magit-tag ()
     39   "Create or delete a tag."
     40   :man-page "git-tag"
     41   ["Arguments"
     42    ("-f" "Force"    ("-f" "--force"))
     43    ("-a" "Annotate" ("-a" "--annotate"))
     44    ("-s" "Sign"     ("-s" "--sign"))
     45    (magit-tag:--local-user)]
     46   [["Create"
     47     ("t"  "tag"     magit-tag-create)
     48     ("r"  "release" magit-tag-release)]
     49    ["Do"
     50     ("k"  "delete"  magit-tag-delete)
     51     ("p"  "prune"   magit-tag-prune)]])
     52 
     53 (defun magit-tag-arguments ()
     54   (transient-args 'magit-tag))
     55 
     56 (transient-define-argument magit-tag:--local-user ()
     57   :description "Sign as"
     58   :class 'transient-option
     59   :shortarg "-u"
     60   :argument "--local-user="
     61   :reader 'magit-read-gpg-signing-key
     62   :history-key 'magit:--gpg-sign)
     63 
     64 ;;;###autoload
     65 (defun magit-tag-create (name rev &optional args)
     66   "Create a new tag with the given NAME at REV.
     67 With a prefix argument annotate the tag.
     68 \n(git tag [--annotate] NAME REV)"
     69   (interactive (list (magit-read-tag "Tag name")
     70                      (magit-read-branch-or-commit "Place tag on")
     71                      (let ((args (magit-tag-arguments)))
     72                        (when current-prefix-arg
     73                          (cl-pushnew "--annotate" args))
     74                        args)))
     75   (magit-run-git-with-editor "tag" args name rev))
     76 
     77 ;;;###autoload
     78 (defun magit-tag-delete (tags)
     79   "Delete one or more tags.
     80 If the region marks multiple tags (and nothing else), then offer
     81 to delete those, otherwise prompt for a single tag to be deleted,
     82 defaulting to the tag at point.
     83 \n(git tag -d TAGS)"
     84   (interactive (list (--if-let (magit-region-values 'tag)
     85                          (magit-confirm t nil "Delete %i tags" nil it)
     86                        (let ((helm-comp-read-use-marked t))
     87                          (magit-read-tag "Delete tag" t)))))
     88   (magit-run-git "tag" "-d" tags))
     89 
     90 ;;;###autoload
     91 (defun magit-tag-prune (tags remote-tags remote)
     92   "Offer to delete tags missing locally from REMOTE, and vice versa."
     93   (interactive
     94    (let* ((remote (magit-read-remote "Prune tags using remote"))
     95           (tags   (magit-list-tags))
     96           (rtags  (prog2 (message "Determining remote tags...")
     97                       (magit-remote-list-tags remote)
     98                     (message "Determining remote tags...done")))
     99           (ltags  (-difference tags rtags))
    100           (rtags  (-difference rtags tags)))
    101      (unless (or ltags rtags)
    102        (message "Same tags exist locally and remotely"))
    103      (unless (magit-confirm t
    104                "Delete %s locally"
    105                "Delete %i tags locally"
    106                'noabort ltags)
    107        (setq ltags nil))
    108      (unless (magit-confirm t
    109                "Delete %s from remote"
    110                "Delete %i tags from remote"
    111                'noabort rtags)
    112        (setq rtags nil))
    113      (list ltags rtags remote)))
    114   (when tags
    115     (magit-call-git "tag" "-d" tags))
    116   (when remote-tags
    117     (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
    118 
    119 (defvar magit-tag-version-regexp-alist
    120   '(("^[-._+ ]?snapshot\\.?$" . -4)
    121     ("^[-._+]$" . -4)
    122     ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4)
    123     ("^[-._+ ]?unknown\\.?$" . -4)
    124     ("^[-._+ ]?alpha\\.?$" . -3)
    125     ("^[-._+ ]?beta\\.?$" . -2)
    126     ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1))
    127   "Overrides `version-regexp-alist' for `magit-tag-release'.
    128 See also `magit-release-tag-regexp'.")
    129 
    130 (defvar magit-release-tag-regexp "\\`\
    131 \\(?1:\\(?:v\\(?:ersion\\)?\\|r\\(?:elease\\)?\\)?[-_]?\\)?\
    132 \\(?2:[0-9]+\\(?:\\.[0-9]+\\)*\
    133 \\(?:-[a-zA-Z0-9-]+\\(?:\\.[a-zA-Z0-9-]+\\)*\\)?\\)\\'"
    134   "Regexp used by `magit-tag-release' to parse release tags.
    135 
    136 The first submatch must match the prefix, if any.  The second
    137 submatch must match the version string.
    138 
    139 If this matches versions that are not dot separated numbers,
    140 then `magit-tag-version-regexp-alist' has to contain entries
    141 for the separators allowed here.")
    142 
    143 ;;;###autoload
    144 (defun magit-tag-release (tag msg &optional args)
    145   "Create a release tag.
    146 
    147 Assume that release tags match `magit-release-tag-regexp'.
    148 
    149 First prompt for the name of the new tag using the highest
    150 existing tag as initial input and leaving it to the user to
    151 increment the desired part of the version string.
    152 
    153 If `--annotate' is enabled, then prompt for the message of the
    154 new tag.  Base the proposed tag message on the message of the
    155 highest tag, provided that that contains the corresponding
    156 version string and substituting the new version string for that.
    157 Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
    158 example, a TAG \"v1.2.3\" and a repository located at something
    159 like \"/path/to/foo-bar\"."
    160   (interactive
    161    (save-match-data
    162      (pcase-let*
    163          ((`(,pver ,ptag ,pmsg) (car (magit--list-releases)))
    164           (tag (read-string "Create release tag: " ptag))
    165           (ver (and (string-match magit-release-tag-regexp tag)
    166                     (match-string 2 tag)))
    167           (args (magit-tag-arguments)))
    168        (list tag
    169              (and (member "--annotate" args)
    170                   (read-string
    171                    (format "Message for %S: " tag)
    172                    (cond ((and pver (string-match (regexp-quote pver) pmsg))
    173                           (replace-match ver t t pmsg))
    174                          ((and ptag (string-match (regexp-quote ptag) pmsg))
    175                           (replace-match tag t t pmsg))
    176                          (t (format "%s %s"
    177                                     (capitalize
    178                                      (file-name-nondirectory
    179                                       (directory-file-name (magit-toplevel))))
    180                                     ver)))))
    181              args))))
    182   (magit-run-git-async "tag" args (and msg (list "-m" msg)) tag)
    183   (set-process-sentinel
    184    magit-this-process
    185    (lambda (process event)
    186      (when (memq (process-status process) '(exit signal))
    187        (magit-process-sentinel process event)
    188        (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments))))))
    189 
    190 (defun magit--list-releases ()
    191   "Return a list of releases.
    192 The list is ordered, beginning with the highest release.
    193 Each release element has the form (VERSION TAG MESSAGE).
    194 `magit-release-tag-regexp' is used to determine whether
    195 a tag qualifies as a release tag."
    196   (save-match-data
    197     (mapcar
    198      #'cdr
    199      (nreverse
    200       (cl-sort (cl-mapcan
    201                 (lambda (line)
    202                   (and (string-match " +" line)
    203                        (let ((tag (substring line 0 (match-beginning 0)))
    204                              (msg (substring line (match-end 0))))
    205                          (and (string-match magit-release-tag-regexp tag)
    206                               (let ((ver (match-string 2 tag))
    207                                     (version-regexp-alist
    208                                      magit-tag-version-regexp-alist))
    209                                 (list (list (version-to-list ver)
    210                                             ver tag msg)))))))
    211                 ;; Cannot rely on "--sort=-version:refname" because
    212                 ;; that gets confused if the version prefix has changed.
    213                 (magit-git-lines "tag" "-n"))
    214                ;; The inverse of this function does not exist.
    215                #'version-list-< :key #'car)))))
    216 
    217 ;;; _
    218 (provide 'magit-tag)
    219 ;;; magit-tag.el ends here