Only failures were reported, so a push could reach the mirror with no way to know short of querying the database by hand. Release runs now report: - start: channel, arch, host, and the commit being built - published: the packages and versions that went out, duration, channel URL - no-changes: the run found nothing to build - promoted: what advance moved between channels, including the rc bootstrap and fast-ring replication - failed: unchanged, plus the commit context the other reports carry Release traffic goes to OMARCHY_RELEASE_CHATBOT_URL, falling back to BASECAMP_CHATBOT_URL, so build reports stop drowning the repository chat the sync workflows post to. bin/setup reports which destination is configured. The published list is captured after the build step because promote moves the files out of build-output, and is capped at 25 entries so a full rebuild does not produce an unreadable wall of chat.
160 lines
4.3 KiB
Bash
160 lines
4.3 KiB
Bash
# Send notifications to Basecamp Campfire via chatbot
|
|
#
|
|
# Two destinations, so release traffic does not drown the repository chat:
|
|
#
|
|
# OMARCHY_RELEASE_CHATBOT_URL release activity (starts, publishes, failures)
|
|
# BASECAMP_CHATBOT_URL everything else, and the fallback when the
|
|
# release URL is unset
|
|
#
|
|
# Each is the full chatbot lines URL from Basecamp, e.g.
|
|
# https://3.basecamp.com/<account>/integrations/<key>/buckets/<project>/chats/<chat>/lines
|
|
#
|
|
# With neither set, notifications are silently skipped.
|
|
|
|
release_chatbot_url() {
|
|
echo "${OMARCHY_RELEASE_CHATBOT_URL:-${BASECAMP_CHATBOT_URL:-}}"
|
|
}
|
|
|
|
notify_basecamp() {
|
|
local content="$1"
|
|
local BASECAMP_CHATBOT_URL
|
|
BASECAMP_CHATBOT_URL=$(release_chatbot_url)
|
|
|
|
if [[ -z "${BASECAMP_CHATBOT_URL:-}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
curl -s -o /dev/null \
|
|
-H "Content-Type: application/json" \
|
|
-d "$(jq -n --arg content "$content" '{content: $content}')" \
|
|
"$BASECAMP_CHATBOT_URL" 2>/dev/null || true
|
|
}
|
|
|
|
basecamp_html_escape() {
|
|
sed -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g'
|
|
}
|
|
|
|
basecamp_strip_ansi() {
|
|
sed -E $'s/\x1B\\[[0-9;?]*[ -/]*[@-~]//g'
|
|
}
|
|
|
|
basecamp_format_log_tail_html() {
|
|
local log_file="$1"
|
|
local lines="${2:-25}"
|
|
|
|
[[ -n "$log_file" && -f "$log_file" ]] || return 0
|
|
|
|
tail -n "$lines" "$log_file" 2>/dev/null |
|
|
tr -d '\r' |
|
|
basecamp_strip_ansi |
|
|
basecamp_html_escape |
|
|
sed ':a;N;$!ba;s/\n/<br>/g'
|
|
}
|
|
|
|
notify_error() {
|
|
local title="$1"
|
|
local details="${2:-}"
|
|
local log_file="${OMARCHY_LOG_FILE:-${LOG_FILE:-}}"
|
|
local log_tail_lines="${BASECAMP_LOG_TAIL_LINES:-25}"
|
|
local log_tail=""
|
|
|
|
local content="🔴 <strong>${title}</strong>"
|
|
if [[ -n "$details" ]]; then
|
|
content+="<br>${details}"
|
|
fi
|
|
|
|
log_tail=$(basecamp_format_log_tail_html "$log_file" "$log_tail_lines")
|
|
if [[ -n "$log_tail" ]]; then
|
|
content+="<br><br><strong>Last ${log_tail_lines} log lines:</strong><br><code>${log_tail}</code>"
|
|
fi
|
|
|
|
notify_basecamp "$content"
|
|
}
|
|
|
|
|
|
# Human-friendly elapsed time: "8m 12s", "45s", "1h 4m".
|
|
format_duration() {
|
|
local seconds="${1:-0}"
|
|
if ((seconds >= 3600)); then
|
|
printf '%dh %dm' $((seconds / 3600)) $(((seconds % 3600) / 60))
|
|
elif ((seconds >= 60)); then
|
|
printf '%dm %ds' $((seconds / 60)) $((seconds % 60))
|
|
else
|
|
printf '%ds' "$seconds"
|
|
fi
|
|
}
|
|
|
|
notify_start() {
|
|
local title="$1"
|
|
local details="${2:-}"
|
|
|
|
local content="🔨 <strong>${title}</strong>"
|
|
[[ -n "$details" ]] && content+="<br>${details}"
|
|
notify_basecamp "$content"
|
|
}
|
|
|
|
notify_success() {
|
|
local title="$1"
|
|
local details="${2:-}"
|
|
|
|
local content="✅ <strong>${title}</strong>"
|
|
[[ -n "$details" ]] && content+="<br>${details}"
|
|
notify_basecamp "$content"
|
|
}
|
|
|
|
notify_info() {
|
|
local title="$1"
|
|
local details="${2:-}"
|
|
|
|
local content="📦 <strong>${title}</strong>"
|
|
[[ -n "$details" ]] && content+="<br>${details}"
|
|
notify_basecamp "$content"
|
|
}
|
|
|
|
# "name-1.2.3-1-x86_64.pkg.tar.zst" -> "name 1.2.3-1". Package file names put
|
|
# the architecture last and the pkgrel before it, so peel from the right.
|
|
package_file_label() {
|
|
local file="$1" stem arch rest rel name_version version name
|
|
stem="${file%.pkg.tar.*}"
|
|
arch="${stem##*-}"
|
|
rest="${stem%-*}"
|
|
rel="${rest##*-}"
|
|
name_version="${rest%-*}"
|
|
version="${name_version##*-}"
|
|
name="${name_version%-*}"
|
|
printf '%s %s-%s' "$name" "$version" "$rel"
|
|
}
|
|
|
|
# Packages sitting in a build-output directory, newest build first. Excludes
|
|
# signatures and the scratch database the builder keeps alongside them.
|
|
built_package_files() {
|
|
local dir="$1"
|
|
[[ -d "$dir" ]] || return 0
|
|
find "$dir" -maxdepth 1 -name '*.pkg.tar.*' ! -name '*.sig' -printf '%f\n' 2>/dev/null |
|
|
grep -v '^omarchy-build\.' | sort
|
|
}
|
|
|
|
# An HTML list of built packages, capped so a 60-package rebuild does not
|
|
# produce an unreadable wall of text in chat.
|
|
format_package_list_html() {
|
|
local files="$1"
|
|
local limit="${2:-25}"
|
|
local count shown=0 line out=""
|
|
|
|
count=$(grep -c '' <<<"$files")
|
|
[[ -z "$files" ]] && count=0
|
|
((count == 0)) && return 0
|
|
|
|
while IFS= read -r line; do
|
|
[[ -z "$line" ]] && continue
|
|
((shown >= limit)) && break
|
|
out+="<br>• $(package_file_label "$line" | basecamp_html_escape)"
|
|
shown=$((shown + 1))
|
|
done <<<"$files"
|
|
|
|
if ((count > shown)); then
|
|
out+="<br>• …and $((count - shown)) more"
|
|
fi
|
|
echo "$out"
|
|
}
|