summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbill-auger <mr.j.spam.me@gmail.com>2024-03-22 17:05:14 -0400
committerbill-auger <mr.j.spam.me@gmail.com>2024-03-28 16:25:54 -0400
commitb552741ca77ddb6c553bb669a0b42d2112d68737 (patch)
tree3880d55118dcb5f3c60792a11e8a4df92c873282
parent75d45bc3bc59717835f22b1ef61761045ae49839 (diff)
notifications.sh: rework and add tests
The previous implementation reported locally-staged packages; but did not account for files which were already staged on the repo server. That would be the case when the `-u` option is used, or sometimes due to error. This implementation reports what was actuially pulbished per `db-update`.
-rw-r--r--Makefile3
-rw-r--r--po/es/librelib.po4
-rw-r--r--po/es/libretools.po4
-rwxr-xr-xsrc/abslibre-tools/librerelease24
-rw-r--r--src/lib/notifications.sh48
-rw-r--r--test/cases/lib-notifications.bats39
-rw-r--r--test/cases/librerelease.bats139
-rw-r--r--test/fixtures/lib-notifications/librerelease-complete-log.log6
-rw-r--r--test/fixtures/lib-notifications/librerelease-debug-pkg.log3
-rw-r--r--test/fixtures/lib-notifications/librerelease-multipkg-any.log10
-rw-r--r--test/fixtures/lib-notifications/librerelease-multipkg-multirepo-any.log11
-rw-r--r--test/fixtures/lib-notifications/librerelease-multipkg-multirepo-multiarch.log4
-rw-r--r--test/fixtures/lib-notifications/librerelease-multirepo-multiarch.log4
13 files changed, 164 insertions, 135 deletions
diff --git a/Makefile b/Makefile
index 3eea508..aff9cbd 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,8 @@ files.src.gen += .srcversion-libretools.mk .srcversion-devtools.mk
nested.subdirs = src po
$(outdir)/check:
- cd $(@D)/test && ./testenv $(TESTENVFLAGS) bats $(TESTFILTERS) cases
+ cd $(@D)/test && ./testenv $(TESTENVFLAGS) \
+ bats $(if $(findstring --no-network,$(TESTENVFLAGS)),--filter-tags !net,) cases
$(outdir)/shellcheck: private shellcheck.flags = --exclude=1090,1091,2016,2059,2064,2164,2191
$(outdir)/shellcheck: private shellcheck.prune = -false
diff --git a/po/es/librelib.po b/po/es/librelib.po
index d59bc11..552840f 100644
--- a/po/es/librelib.po
+++ b/po/es/librelib.po
@@ -286,7 +286,3 @@ msgstr "no se ha dado ningún archivo"
#: src/lib/messages.sh:60
msgid "panic: malformed call to internal function"
msgstr "pánico: llamada malformada a la función interna"
-
-#: src/lib/notifications.sh:26
-msgid "Notifying pbot:"
-msgstr "Notificando pbot:"
diff --git a/po/es/libretools.po b/po/es/libretools.po
index 880e915..1d953bc 100644
--- a/po/es/libretools.po
+++ b/po/es/libretools.po
@@ -340,6 +340,10 @@ msgstr "Solo subir; no ejecutar db-update en el servidor"
msgid "Dry-run; don't actually do anything"
msgstr "Dry-run; no hace nada en realidad"
+#: src/abslibre-tools/librerelease:345
+msgid "Notifying pbot:"
+msgstr "Notificando pbot:"
+
#: src/abslibre-tools/librerelease:139
msgid "This program should be run as unprivileged user"
msgstr "Este programa debiera ser ejecutado como usuario normal"
diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease
index a94c166..9c48ac7 100755
--- a/src/abslibre-tools/librerelease
+++ b/src/abslibre-tools/librerelease
@@ -202,7 +202,7 @@ release() {
local dbupdate_log="$(mktemp -t ${0##*/}_log.XXXXXXXXXX)"
local mkdir_cmd="mkdir -p -- ${TIER0_STAGING@Q} && cd ${TIER0_STAGING@Q} && xargs -0r mkdir -pv --"
local dbupdate_cmd="STAGING=${TIER0_STAGING@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update"
- local upload_size
+ local upload_size pbotsay_msg pbotsay_cmd
trap "rm -f -- ${file_list@Q} ${dbupdate_log@Q}" INT RETURN TERM
@@ -263,7 +263,20 @@ release() {
## publish ##
msg "Running db-update on repos"
- if ${SSH_CMD[*]} "${dbupdate_cmd}"; then # eg: ssh -p 1863 autobuilder@repo.parabola.nu STAGING='staging/' DBSCRIPTS_CONFIG='/etc/dbscripts/config.local.parabola' db-update
+ (
+ # this contraption allows detecting `db-update` exit failure,
+ # while logging output both to file and to the local shell in real-time,
+ # while preserving (restoring) colors lost in the pipeline
+ set -o pipefail ; ${SSH_CMD[*]} "$dbupdate_cmd" | tee "$dbupdate_log" |
+ while read line ; do ( [[ "$line" =~ ^==\> ]] && msg "${line#==\> }" ) ||
+ ( [[ "$line" =~ ^\ *-\> ]] && msg2 "${line#*\> }" ) ||
+ echo "$line" ; done
+ )
+
+ if grep -Eq "^==> Updating \[" "$dbupdate_log"; then
+ pbotsay_msg=$(release_notification "${TIER0_LOGIN:-${LIBREUSER}}" < "$dbupdate_log")
+ pbotsay_cmd="if type pbot-say &>/dev/null ; then pbot-say ${pbotsay_msg@Q} ; fi"
+
if [[ -n $HOOKPOSTRELEASE ]]; then
msg "Running HOOKPOSTRELEASE..."
(
@@ -273,11 +286,10 @@ release() {
fi
# notify pbot of the excellent work that we have done today
- notify_release ${SSH_CMD[*]} < $file_list
-
- return $EXIT_SUCCESS
+ msg2 "$(_ "Notifying pbot:")" ; print " $pbotsay_msg" ;
+ ${SSH_CMD[*]} "$pbotsay_cmd" &> /dev/null || :
else
- return $EXIT_FAILURE
+ msg2 "Nothing was published"
fi
}
diff --git a/src/lib/notifications.sh b/src/lib/notifications.sh
index 2457dbd..0c3b947 100644
--- a/src/lib/notifications.sh
+++ b/src/lib/notifications.sh
@@ -1,29 +1,25 @@
-# process librerelease::$file_list via STDIN
-notify_release() # ( ssh_cmd* ) file_list->STDIN
+# parse `librerelease` `db-update` log via STDIN,
+# and emit formatted notification message
+release_notification() # ( hacker ) dbupdate_log->STDIN
{
- local ssh_cmd=( $* )
- local repo_user=${REPOUSER:-${LIBREUSER:-somebody}}
- local select_rx='\.pkg\.tar\.[^\.]+$'
- local reject_rx='-debug-'
- # example "selected" $file_list entry, to be fed through $filename_rx:
- # libre/gst-plugins-bad-1.22.8-1.parabola1-x86_64.pkg.tar.zst
- # (repo )/(pkgname )- : (pkgver )- -(arch )
- local filename_rx="^([a-z-]+)/([0-9A-Za-z\._@\+\-]+)-([0-9]+:)?([0-9A-Za-z\._]+)-[^/-]+-([0-9a-z_]+)${select_rx}"
- local filename_subst='(\2 \4)->\1/\5' # eg: (iceweasel 121.0.1)->libre/x86_64
- local filename_sed="s|${filename_rx}|${filename_subst}|"
- local filename
- local releases=( $(while read -r -d '' # process librerelease::$file_list via STDIN
- do filename="$REPLY"
- [[ "${filename}" =~ ${select_rx} ]] || continue
- [[ "${filename}" =~ ${reject_rx} ]] && continue || :
+ local hacker=${1:-somebody}
+ # (pkgname )- : (pkgver )- -(arch )
+ local filename_rx="^([0-9A-Za-z\._@\+\-]+)-([0-9]+:)?([0-9A-Za-z\._]+)-[^/-]+-([0-9a-z_]+)\.pkg\.tar\.[^\.]+$"
+ local repo pkg arch pkgname pkgver
- sed -E "${filename_sed}" <<< ${filename} || :
- done | sort -u | xargs || :) )
- local pbotsay_msg="$(printf "%s just published:" ${repo_user}) ${releases[@]}"
- local pbotsay_cmd="which pbot-say &> /dev/null && pbot-say '${pbotsay_msg}'"
-
- if [[ ${ssh_cmd[0]} == ssh ]] && (( ${#releases[@]} )); then
- msg2 "$(_ "Notifying pbot:")" ; print " ${pbotsay_msg}" ;
- ${ssh_cmd[*]} "${pbotsay_cmd}" &> /dev/null || :
- fi
+ printf "${hacker} just published: "
+ grep -E "^==> Updating |^ -> [^ ]+ \([^ )]+\)" |
+ while read line
+ do if [[ "${line}" =~ ^==\>\ Updating\ \[([^\]]+)\]...$ ]]
+ then repo=${BASH_REMATCH[1]}
+ elif [[ "${line}" =~ ^\ *-\>\ ([^\ ]+)\ \(([^\ ]+)\)$ ]]
+ then pkg=${BASH_REMATCH[1]} arch=${BASH_REMATCH[2]}
+ if [[ "${pkg}" =~ ${filename_rx} ]]
+ then pkgname=${BASH_REMATCH[1]} pkgver=${BASH_REMATCH[3]}
+ if [[ ! "${pkg}" =~ '-debug-' ]]
+ then echo "(${pkgname} ${pkgver})->${repo}/${arch}"
+ fi
+ fi
+ fi
+ done | LANG=C sort -u | xargs
}
diff --git a/test/cases/lib-notifications.bats b/test/cases/lib-notifications.bats
new file mode 100644
index 0000000..b45c3ff
--- /dev/null
+++ b/test/cases/lib-notifications.bats
@@ -0,0 +1,39 @@
+readonly FIXURES_DIR=./fixtures//lib-notifications
+readonly TEST_SCRIPT="source ../src/lib/notifications.sh ; release_notification tester < "
+
+
+@test "lib/notifications.sh parses db-update log" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-complete-log.log"
+# echo "librerelease-complete-log.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (foo 1.2.3)->libre-testing/i686" ]]
+}
+
+@test "lib/notifications.sh parses db-update log - debug-pkg" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-debug-pkg.log"
+# echo "librerelease-debug-pkg.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (foo 1.2.3)->libre/i686" ]]
+}
+
+@test "lib/notifications.sh parses db-update log - multipkg-any" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-multipkg-any.log"
+# echo "librerelease-multipkg-any.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (gitget 20240221.1)->libre/armv7h (gitget 20240221.1)->libre/i686 (gitget 20240221.1)->libre/x86_64 (librelib 20240221.1)->libre/armv7h (librelib 20240221.1)->libre/i686 (librelib 20240221.1)->libre/x86_64 (libretools 20240221.1)->libre/armv7h (libretools 20240221.1)->libre/i686 (libretools 20240221.1)->libre/x86_64" ]]
+}
+
+@test "lib/notifications.sh parses db-update log - multipkg-multirepo-any" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-multipkg-multirepo-any.log"
+# echo "librerelease-multipkg-multirepo-any.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (gitget 20240221.1)->libre-testing/i686 (gitget 20240221.1)->libre-testing/x86_64 (gitget 20240221.1)->libre/armv7h (librelib 20240221.1)->libre-testing/i686 (librelib 20240221.1)->libre-testing/x86_64 (librelib 20240221.1)->libre/armv7h (libretools 20240221.1)->libre-testing/i686 (libretools 20240221.1)->libre-testing/x86_64 (libretools 20240221.1)->libre/armv7h" ]]
+}
+
+@test "lib/notifications.sh parses db-update log - multipkg-multirepo-multiarch" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-multipkg-multirepo-multiarch.log"
+# echo "librerelease-multipkg-multirepo-multiarch.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (bar 1.2.3)->libre/i686 (foo 1.2.3)->libre-testing/x86_64" ]]
+}
+
+@test "lib/notifications.sh parses db-update log - multirepo-multiarch" {
+ run bash -c "${TEST_SCRIPT} $FIXURES_DIR/librerelease-multirepo-multiarch.log"
+# echo "librerelease-multirepo-multiarch.log=${output}" >&3
+ [[ "${output}" =~ "tester just published: (foo 1.2.3)->libre-testing/x86_64 (foo 1.2.3)->libre/i686" ]]
+}
diff --git a/test/cases/librerelease.bats b/test/cases/librerelease.bats
index a79ff6d..7f982fd 100644
--- a/test/cases/librerelease.bats
+++ b/test/cases/librerelease.bats
@@ -3,6 +3,30 @@ load ../lib/common
# bats file_tags=net
+# Stub server-side `db-update` for SSH localhost to run
+DBUPDATE_STUB()
+{
+ cat <<-eot
+#!/bin/bash
+echo "==> Updating [fake-repo]"
+{
+ printf '%s\n' "\$DBSCRIPTS_CONFIG"
+ readlink -f -- "\$STAGING"
+ find "\$STAGING" -printf '%P\n' | LC_COLLATE=C sort
+} > ${tmpdir@Q}/log.txt
+eot
+}
+
+# Stub server-side `pbot-say` for SSH localhost to run
+PBOTSAY_STUB()
+{
+ cat <<-eot
+#!/bin/bash
+echo "\$*" >${tmpdir@Q}/pbot.txt
+eot
+}
+
+
setup() {
common_setup
@@ -99,6 +123,7 @@ teardown() {
@test "librerelease fails if TIER0_HOST not set" {
unset TIER0_HOST
+ sed -i 's|TIER0_HOST=.*|TIER0_HOST=|' "$XDG_CONFIG_HOME/libretools/libretools.conf"
local workdir="$tmpdir/workdir"
mkdir -p "$workdir/staging/repo1" "$workdir/staging/repo2/sub"
@@ -111,7 +136,7 @@ teardown() {
LC_ALL=C librerelease -l >"$tmpdir/stdout" 2>"$tmpdir/stderr" || status=$?
[[ $status != 0 ]]
- empty "$tmpdir/stdout"
+ grep "libretools.conf variables may have changed" "$tmpdir/stdout"
grep TIER0_HOST "$tmpdir/stderr"
}
@@ -131,21 +156,13 @@ teardown() {
LC_ALL=C librerelease -l >"$tmpdir/stdout" 2>"$tmpdir/stderr" || status=$?
[[ $status != 0 ]]
- empty "$tmpdir/stdout"
+ grep "libretools.conf variables may have changed" "$tmpdir/stdout"
grep DBSCRIPTS_CONFIG "$tmpdir/stderr"
}
-@test "librerelease runs" {
- # Add a stub db-update so that when we ssh to localhost it has
- # something to run.
- install -Dm755 /dev/stdin "$tmpdir/bin/db-update" <<-eot
- #!/bin/bash
- {
- printf '%s\n' "\$DBSCRIPTS_CONFIG"
- readlink -f -- "\$STAGING"
- find "\$STAGING" -printf '%P\n' | LC_COLLATE=C sort
- } > ${tmpdir@Q}/log.txt
- eot
+@test "librerelease publishes packages successfully" {
+ # Add server-side stub
+ install -Dm755 /dev/stdin "$tmpdir/bin/db-update" < <(DBUPDATE_STUB) # writes log.txt
PATH=$tmpdir/bin:$PATH
# Log which directories the hooks are run in.
@@ -190,28 +207,11 @@ teardown() {
}
@test "librerelease notifies pbot" {
- # Add a stub db-update pbot-say so that when we ssh to localhost it has
- # something to run.
- install -Dm755 /dev/stdin "$tmpdir/bin/db-update" <<-eot
- #!/bin/bash
- {
- printf '%s\n' "\$DBSCRIPTS_CONFIG"
- readlink -f -- "\$STAGING"
- find "\$STAGING" -printf '%P\n' | LC_COLLATE=C sort
- } > ${tmpdir@Q}/log.txt
- eot
- install -Dm755 /dev/stdin "$tmpdir/bin/pbot-say" <<-eot
- #!/bin/bash
- echo "\$*" >${tmpdir@Q}/pbot.txt
- eot
+ # Add server-side stubs
+ install -Dm755 /dev/stdin "$tmpdir/bin/db-update" < <(DBUPDATE_STUB) # writes log.txt
+ install -Dm755 /dev/stdin "$tmpdir/bin/pbot-say" < <(PBOTSAY_STUB ) # writes pbot.txt
PATH=$tmpdir/bin:$PATH
- # Log which directories the hooks are run in.
- cat >> "$XDG_CONFIG_HOME/libretools/libretools.conf" <<-eot
- HOOKPRERELEASE='pwd > ${tmpdir@Q}/prerelease.txt'
- HOOKPOSTRELEASE='pwd > ${tmpdir@Q}/postrelease.txt'
- eot
-
# Make some files to stage
local workdir="$tmpdir/workdir"
mkdir -p "$workdir/staging/repo1" "$workdir/staging/repo2/sub"
@@ -224,53 +224,13 @@ teardown() {
# Run
librerelease
- # Make sure everything went OK
- pwd > "$tmpdir/pwd.txt"
- cat > "$tmpdir/log-correct.txt" <<-eot
- /etc/dbscripts/config.local.phony
- $(readlink -f -- "$tmpdir/srv-staging")
-
- repo1
- repo1/file1
- repo1/file1.sig
- repo1/file2
- repo1/file2.sig
- repo2
- repo2/file with spaces
- repo2/file with spaces.sig
- repo2/sub
- repo2/sub/subfolder
- repo2/sub/subfolder.sig
- eot
- diff -u "$tmpdir/log-correct.txt" "$tmpdir/log.txt"
- diff -u "$tmpdir/pwd.txt" "$tmpdir/prerelease.txt"
- diff -u "$tmpdir/pwd.txt" "$tmpdir/postrelease.txt"
+ # Check that pbot gets notified
grep 'just published' "$tmpdir/pbot.txt"
}
-@test "librerelease logs in as TIER0_LOGIN" {
- # Add a stub db-update pbot-say so that when we ssh to localhost it has
- # something to run.
- install -Dm755 /dev/stdin "$tmpdir/bin/db-update" <<-eot
- #!/bin/bash
- {
- printf '%s\n' "\$DBSCRIPTS_CONFIG"
- readlink -f -- "\$STAGING"
- find "\$STAGING" -printf '%P\n' | LC_COLLATE=C sort
- } > ${tmpdir@Q}/log.txt
- eot
- install -Dm755 /dev/stdin "$tmpdir/bin/pbot-say" <<-eot
- #!/bin/bash
- echo "\$*" >${tmpdir@Q}/pbot.txt
- eot
+@test "librerelease logs-in as TIER0_LOGIN" {
PATH=$tmpdir/bin:$PATH
- # Log which directories the hooks are run in.
- cat >> "$XDG_CONFIG_HOME/libretools/libretools.conf" <<-eot
- HOOKPRERELEASE='pwd > ${tmpdir@Q}/prerelease.txt'
- HOOKPOSTRELEASE='pwd > ${tmpdir@Q}/postrelease.txt'
- eot
-
# Make some files to stage
local workdir="$tmpdir/workdir"
mkdir -p "$workdir/staging/repo1" "$workdir/staging/repo2/sub"
@@ -281,28 +241,11 @@ teardown() {
"$workdir/staging/repo2/sub/subfolder"
# Run
- TIER0_LOGIN=tier0-user librerelease
-
- # Make sure everything went OK
- pwd > "$tmpdir/pwd.txt"
- cat > "$tmpdir/log-correct.txt" <<-eot
- /etc/dbscripts/config.local.phony
- $(readlink -f -- "$tmpdir/srv-staging")
+ echo "TIER0_LOGIN=tier0-user" >> "$XDG_CONFIG_HOME/libretools/libretools.conf"
+ librerelease >"$tmpdir/stdout" 2>"$tmpdir/stderr" || status=$?
- repo1
- repo1/file1
- repo1/file1.sig
- repo1/file2
- repo1/file2.sig
- repo2
- repo2/file with spaces
- repo2/file with spaces.sig
- repo2/sub
- repo2/sub/subfolder
- repo2/sub/subfolder.sig
- eot
- diff -u "$tmpdir/log-correct.txt" "$tmpdir/log.txt"
- diff -u "$tmpdir/pwd.txt" "$tmpdir/prerelease.txt"
- diff -u "$tmpdir/pwd.txt" "$tmpdir/postrelease.txt"
- grep 'tier0-user just published' "$tmpdir/pbot.txt"
+ # Check that tier0-user was the SSH login
+ [[ $status != 0 ]]
+ empty "$tmpdir/stdout"
+ grep "tier0-user@127.0.0.1: Permission denied" "$tmpdir/stderr"
}
diff --git a/test/fixtures/lib-notifications/librerelease-complete-log.log b/test/fixtures/lib-notifications/librerelease-complete-log.log
new file mode 100644
index 0000000..ec4c8d8
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-complete-log.log
@@ -0,0 +1,6 @@
+copied 'sources/parabola/foo-1.2.3-4-i686.src.tar.gz' -> '/srv/repo/main/sources/parabola/foo-1.2.3-4-i686.src.tar.gz'
+removed 'sources/parabola/foo-1.2.3-4-i686.src.tar.gz'
+copied 'sources/parabola/foo-1.2.3-4-i686.src.tar.gz.sig' -> '/srv/repo/main/sources/parabola/foo-1.2.3-4-i686.src.tar.gz.sig'
+removed 'sources/parabola/foo-1.2.3-4-i686.src.tar.gz.sig'
+==> Updating [libre-testing]...
+ -> foo-1.2.3-4-i686.pkg.tar.zst (i686)
diff --git a/test/fixtures/lib-notifications/librerelease-debug-pkg.log b/test/fixtures/lib-notifications/librerelease-debug-pkg.log
new file mode 100644
index 0000000..ac90d2f
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-debug-pkg.log
@@ -0,0 +1,3 @@
+==> Updating [libre]...
+ -> foo-1.2.3-4-i686.pkg.tar.zst (i686)
+ -> foo-debug-1.2.3-4-i686.pkg.tar.zst (i686)
diff --git a/test/fixtures/lib-notifications/librerelease-multipkg-any.log b/test/fixtures/lib-notifications/librerelease-multipkg-any.log
new file mode 100644
index 0000000..4ccf129
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-multipkg-any.log
@@ -0,0 +1,10 @@
+==> Updating [libre]...
+ -> gitget-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> gitget-20240221.1-3-any.pkg.tar.zst (i686)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (i686)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (i686)
+ -> gitget-20240221.1-3-any.pkg.tar.zst (armv7h)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (armv7h)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (armv7h)
diff --git a/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-any.log b/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-any.log
new file mode 100644
index 0000000..35a76ad
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-any.log
@@ -0,0 +1,11 @@
+==> Updating [libre-testing]...
+ -> gitget-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (x86_64)
+ -> gitget-20240221.1-3-any.pkg.tar.zst (i686)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (i686)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (i686)
+==> Updating [libre]...
+ -> gitget-20240221.1-3-any.pkg.tar.zst (armv7h)
+ -> librelib-20240221.1-3-any.pkg.tar.zst (armv7h)
+ -> libretools-20240221.1-3-any.pkg.tar.zst (armv7h)
diff --git a/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-multiarch.log b/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-multiarch.log
new file mode 100644
index 0000000..7dade39
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-multipkg-multirepo-multiarch.log
@@ -0,0 +1,4 @@
+==> Updating [libre-testing]...
+ -> foo-1.2.3-4-x86_64.pkg.tar.zst (x86_64)
+==> Updating [libre]...
+ -> bar-1.2.3-4-i686.pkg.tar.zst (i686)
diff --git a/test/fixtures/lib-notifications/librerelease-multirepo-multiarch.log b/test/fixtures/lib-notifications/librerelease-multirepo-multiarch.log
new file mode 100644
index 0000000..17810e4
--- /dev/null
+++ b/test/fixtures/lib-notifications/librerelease-multirepo-multiarch.log
@@ -0,0 +1,4 @@
+==> Updating [libre-testing]...
+ -> foo-1.2.3-4-x86_64.pkg.tar.zst (x86_64)
+==> Updating [libre]...
+ -> foo-1.2.3-4-i686.pkg.tar.zst (i686)