aboutsummaryrefslogtreecommitdiff
path: root/watch-git-tags.sh
diff options
context:
space:
mode:
Diffstat (limited to 'watch-git-tags.sh')
-rw-r--r--watch-git-tags.sh84
1 files changed, 84 insertions, 0 deletions
diff --git a/watch-git-tags.sh b/watch-git-tags.sh
new file mode 100644
index 0000000..b9fdce8
--- /dev/null
+++ b/watch-git-tags.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# List sorted local tags
+tags_local() {
+ for repo ; do
+ git -C "$repo" tag --list | LC_COLLATE=C sort
+ done
+}
+
+# List sorted remote tags
+tags_remote() {
+ for repo ; do
+ git -C "$repo" ls-remote --quiet --refs --tags ||
+ printf >&2 'Failed to retrieve tags for repository %s\n' "$PWD"
+ done |
+ while read -r _ tag ; do
+ tag=${tag#refs/tags/}
+ printf '%s\n' "$tag"
+ done
+}
+
+# Create a temporary directory with name in $td, and handle POSIX-ish traps to
+# remove it when the script exits; requires mktemp(1) (not POSIX)
+td=$(mktemp -d) || exit
+cleanup() {
+ [ -n "$td" ] || return
+ rm -fr -- "$td"
+}
+for sig in EXIT HUP INT TERM ; do
+ # shellcheck disable=SC2064
+ trap "cleanup $sig" "$sig"
+done
+
+# Use current directory if no other arguments
+[ "$#" -gt 0 ] || set -- .
+
+# Iterate through each repo in a subshell in parallel
+for repo ; do (
+
+ # Make a temporary directory with a hash in its name for uniqueness
+ name=$(printf '%s' "$repo" | sed 's:/:_:g')
+ cksum=$(printf '%s' "$repo" | cksum | sed 's:[^0-9].*::')
+ sd=$td/$name.$cksum
+ mkdir -- "$sd" "$sd"/tags || exit
+
+ # Step in and write repo path to file
+ cd -- "$sd" || exit
+ printf '%s\n' "$repo" > path || exit
+
+ # Write local and remote tags to files
+ tags_local "$repo" > tags/local || exit
+ tags_remote "$repo" > tags/remote || exit
+
+ # Write new tags to file
+ LC_COLLATE=C comm -13 -- tags/local tags/remote > tags/new
+
+ # Attempt to quietly fetch new tags so that we don't notify about the same
+ # ones next time
+ [ -s tags/new ] || exit
+ git -C "$repo" fetch --quiet --tags
+
+) & done
+
+# Wait for all of those to finish
+wait
+
+# Iterate through the temp dirs in order
+for dir in "$td"/* ; do (
+ cd -- "$dir" || exit
+
+ # Look for non-zero "new" files (at least one new tag)
+ [ -s tags/new ] || exit
+
+ # Print repository path and new tags
+ cat path
+ while read -r tag ; do
+ printf '* %s\n' "$tag"
+ done < tags/new
+
+) ; done
+
+# Haven't yet decided on exit value semantics; for the moment, if it completes,
+# exit success
+exit 0