diff mbox series

[bug#69780,v2,4/5] git authenticate: Install pre-push and post-checkout hooks.

Message ID 8361a793c4b4e18115c0e68e6065a7846e759795.1712522119.git.ludo@gnu.org
State New
Headers show
Series [bug#69780,v2,1/5] git authenticate: Record introduction and keyring in ‘.git/config’. | expand

Commit Message

Ludovic Courtès April 7, 2024, 8:38 p.m. UTC
* guix/scripts/git/authenticate.scm (install-hooks): New procedure.
(guix-git-authenticate): Use it.
* doc/guix.texi (Invoking guix git authenticate): Document it.

Change-Id: I4464a33193186e85b476a12740e54412bd58429c
---
 doc/guix.texi                     |  5 ++++
 guix/scripts/git/authenticate.scm | 49 ++++++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 6ff0e76d97..9db0ff865d 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -7715,6 +7715,11 @@  Invoking guix git authenticate
 	keyring = keyring
 @end smallexample
 
+The first run also attempts to install pre-push and post-merge hooks,
+such that @command{guix git authenticate} is invoked as soon as you run
+@command{git push}, @command{git pull}, and related commands; it does
+not overwrite preexisting hooks though.
+
 The command-line options described below allow you to fine-tune the
 process.
 
diff --git a/guix/scripts/git/authenticate.scm b/guix/scripts/git/authenticate.scm
index 0797cba0b6..e3ecb67c89 100644
--- a/guix/scripts/git/authenticate.scm
+++ b/guix/scripts/git/authenticate.scm
@@ -148,6 +148,52 @@  (define* (record-configuration repository
       (warning (G_ "could not record introduction and keyring configuration\
  (Guile-Git too old?)~%"))))
 
+(define (install-hooks repository)
+  "Attempt to install in REPOSITORY hooks that invoke 'guix git authenticate'.
+Bail out if one of these already exists."
+  ;; Guile-Git < 0.7.0 lacks 'repository-common-directory'.
+  (if (module-defined? (resolve-interface '(git))
+                       'repository-common-directory)
+      (let ()
+        (define directory
+          (repository-common-directory repository))
+
+        (define pre-push-hook
+          (in-vicinity directory "hooks/pre-push"))
+
+        (define post-merge-hook
+          (in-vicinity directory "hooks/post-merge"))
+
+        (if (or (file-exists? pre-push-hook)
+                (file-exists? post-merge-hook))
+            (begin
+              (warning (G_ "not overriding pre-existing hooks '~a' and '~a'~%")
+                       pre-push-hook post-merge-hook)
+              (display-hint (G_ "Consider running @command{guix git authenticate}
+from your pre-push and post-merge hooks so your repository is automatically
+authenticated before you push and when you pull updates.")))
+            (begin
+              (call-with-output-file pre-push-hook
+                (lambda (port)
+                  (format port "#!/bin/sh
+# Installed by 'guix git authenticate'.
+set -e
+while read local_ref local_oid remote_ref remote_oid
+do
+  guix git authenticate --end=\"$local_oid\"
+done\n")
+                  (chmod port #o755)))
+              (call-with-output-file post-merge-hook
+                (lambda (port)
+                  (format port "#!/bin/sh
+# Installed by 'guix git authenticate'.
+exec guix git authenticate\n")
+                  (chmod port #o755)))
+              (info (G_ "installed hooks '~a' and '~a'~%")
+                    pre-push-hook post-merge-hook))))
+      (warning (G_ "cannot determine where to install hooks\
+ (Guile-Git too old?)~%"))))
+
 (define (show-stats stats)
   "Display STATS, an alist containing commit signing stats as returned by
 'authenticate-repository'."
@@ -271,7 +317,8 @@  (define (guix-git-authenticate . args)
        (unless (configured? repository)
          (record-configuration repository
                                #:commit commit #:signer signer
-                               #:keyring-reference keyring))
+                               #:keyring-reference keyring)
+         (install-hooks repository))
 
        (when (and show-stats? (not (null? stats)))
          (show-stats stats))