aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-07-03 12:10:17 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-07-03 12:10:17 -0700
commita0ea69134bb555e537b019633217b19acdaf1930 (patch)
tree427250ec3d37b27de3d8dadc58d1c9c304816af1
parenta074f5b847aef8b80ca946900e057a914c5c08f6 (diff)
downloadger2err-a0ea69134bb555e537b019633217b19acdaf1930.tar.gz
ger2err-a0ea69134bb555e537b019633217b19acdaf1930.tar.bz2
ger2err-a0ea69134bb555e537b019633217b19acdaf1930.zip
Initial version.
-rwxr-xr-xger2err147
1 files changed, 147 insertions, 0 deletions
diff --git a/ger2err b/ger2err
new file mode 100755
index 0000000..fd68719
--- /dev/null
+++ b/ger2err
@@ -0,0 +1,147 @@
+#!/usr/local/bin/txr --lisp
+;; vim:filetype=tl:lisp:
+
+(defvarl %prog% *load-path*)
+
+(defvar *gerrit-curl*)
+
+(defstruct patch-set ()
+ num
+ (files (hash)))
+
+(defstruct file ()
+ path
+ (comments (vec)))
+
+(defstruct comment ()
+ line
+ chr
+ unresolved
+ user
+ name
+ lines)
+
+(defun fatal (. args)
+ [apply format t `@{%prog%}: @(car args)\n` (cdr args)]
+ (exit nil))
+
+(defun gerrit-config (user-id password server)
+ (if (contains ":" user-id)
+ (error "user-id ~a may not have a \":\" (colon) in it." user-id))
+ (set *gerrit-curl* `curl -H Accept-Encoding:gzip \ \
+ -s -k -u @{user-id}:@{password} @{server}`))
+
+(defun gerrit (api)
+ (unless *gerrit-curl*
+ (error "~s: configure with gerrit-config function" 'gerrit))
+ (with-stream (s (open-command `@{*gerrit-curl*}@api` "rz"))
+ (let ((tag (get-line s)))
+ (if (nequal tag ")]}'")
+ (fatal "error response from server: ~a" tag)))
+ (get-json s)))
+
+(defun get-gerrit-comments (change-id : resolved-too)
+ (let ((ps-hash (hash)))
+ (dohash (path comments
+ (catch
+ (gerrit `/a/changes/@{change-id}/comments/`)
+ (syntax-error (. rest)
+ (fatal `error retrieving Change-Id: @{change-id}`)))
+ ps-hash)
+ (each ((cmt comments))
+ (let ((unresolved [cmt "unresolved"]))
+ (when (or unresolved resolved-too)
+ (let* ((line (int-flo (or [cmt "line"] 0.0)))
+ (rng [cmt "range"])
+ (endchr [rng "end_character"])
+ (ps-num (int-flo [cmt "patch_set"]))
+ (auth [cmt "author"])
+ (name [auth "name"])
+ (username [auth "username"])
+ (unresolved [cmt "unresolved"])
+ (lines (spl "\n" [cmt "message"]))
+ (patch-set (or [ps-hash ps-num]
+ (set [ps-hash ps-num]
+ (new patch-set num ps-num))))
+ (file (or [patch-set.files path]
+ (set [patch-set.files path]
+ (new file path path)))))
+ (vec-push file.comments
+ (new comment
+ line line
+ chr endchr
+ unresolved unresolved
+ user username
+ name name
+ lines lines)))))))))
+
+(defun print-as-errors (patchset)
+ (put-line `comments from patch set @{patchset.num}`)
+ (each ((file (sort (hash-values patchset.files) : .path)))
+ (each ((cmt file.comments))
+ (put-line `@{file.path}:@{cmt.line}:\
+ @(if cmt.chr `@{cmt.chr}:`) \ \
+ @(if cmt.unresolved "un")resolved comment by\ \
+ @{cmt.name} (@{cmt.user})`)
+ (each ((ln cmt.lines))
+ (put-line `\t@ln`)))))
+
+(define-option-struct opts ()
+ (nil help :bool "List this help text.")
+ (p patchset :str "Patchset selection. Valid choices are all,\ \
+ highest or a positive decimal integer\ \
+ with no leading zeros. Default is all.")
+ (r resolved :bool "Resolved comments too.")
+ (s server :str "URL of gerrit server, with no trailing slash:\ \
+ for example, https://example.com/gerrit .\ \
+ May be given via GER2ERR_SERVER\ \
+ environment variable.")
+ (u userid :str "HTTP user ID for Gerrit\ \
+ (Different from regular Gerrit user ID).\ \
+ May be given via GER2ERR_USERID\ \
+ environment variable.")
+ (w password :str "HTTP password for Gerrit\ \
+ (Different from regular Gerrit password;\ \
+ generated in Gerrit config GUI).\ \
+ May be given via GER2ERR_PASSWORD\ \
+ environment variable."))
+
+(catch
+ (let ((o (new opts))
+ (ps-sel :all))
+ o.(getopts *args*)
+ (when o.help
+ (put-line `\nUsage:\n\n @{%prog%} [options] change-id`)
+ o.(opthelp)
+ (exit nil))
+
+ (match-case o.patchset
+ (nil)
+ ("all" (set ps-sel :all))
+ ("highest" (set ps-sel :highest))
+ (`@{num #/[1-9][0-9]*/}` (set ps-sel (int-str num)))
+ (@else (fatal "bad argument to --patchset")))
+
+ (gerrit-config (or o.userid
+ (getenv "GER2ERR_USERID")
+ (fatal "userid required"))
+ (or o.password
+ (getenv "GER2ERR_PASSWORD")
+ (fatal "password required"))
+ (or o.server
+ (getenv "GER2ERR_SERVER")
+ (fatal "server URL required")))
+
+ (match-case o.out-args
+ ((@change-id) (let ((ps-hash (get-gerrit-comments change-id o.resolved)))
+ (match-case ps-sel
+ (@(or (integerp @psnum)
+ @(and :highest
+ @(with psnum [find-max-key ps-hash : car])))
+ (print-as-errors [ps-hash psnum]))
+ (@else
+ (each ((psnum (sort (hash-keys ps-hash))))
+ (print-as-errors [ps-hash psnum]))))))
+ (@else (fatal "change-id argument required: use --help for usage."))))
+ (opt-error (msg)
+ (fatal msg)))