Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/verify-split-files.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ on:
- "tests/forge-clean-install.sh"
- "tests/db-helper-context.sh"
- "tests/forge-tag-spelling.sh"
- "tests/forge-deb-services.sh"
- "tests/cs-clear.sh"
- "tests/forge-appversion-scope.sh"
- "tests/forge-singlefile-compressed.sh"
Expand Down Expand Up @@ -141,6 +142,7 @@ on:
- "tests/forge-clean-install.sh"
- "tests/db-helper-context.sh"
- "tests/forge-tag-spelling.sh"
- "tests/forge-deb-services.sh"
- "tests/cs-clear.sh"
- "tests/forge-appversion-scope.sh"
- "tests/forge-singlefile-compressed.sh"
Expand Down Expand Up @@ -301,6 +303,8 @@ jobs:
run: bash tests/db-helper-context.sh
- name: Pinned tag with or without its v tests
run: bash tests/forge-tag-spelling.sh
- name: Services after a .deb install tests
run: bash tests/forge-deb-services.sh
- name: Screen clear without a terminal tests
run: bash tests/cs-clear.sh
- name: App version pin and .deb stamp tests
Expand Down
1 change: 1 addition & 0 deletions lib/API.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ _docker_setup_lxcfs_visibility
_download_source_tarball
_forge_asset_urls
_forge_curl
_forge_deb_units
_forge_descriptor
_forge_designated_release
_forge_disk_full
Expand Down
29 changes: 29 additions & 0 deletions lib/forge.func
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,13 @@ _forge_is_script_app() {
[[ "$fetched" == *"$script"* || "$script" == *"$fetched"* ]]
}

# Service units a package ships, templates (foo@) left out; none without systemd.
_forge_deb_units() {
command -v systemctl >/dev/null 2>&1 || return 0
[[ -d /run/systemd/system ]] || return 0
dpkg -L "$1" 2>/dev/null | grep -E '/systemd/system/[^/@]+\.service$' | sed 's#.*/##' | sort -u
}

# ------------------------------------------------------------------------------
# fetch_and_deploy_release()
#
Expand Down Expand Up @@ -2460,13 +2467,35 @@ fetch_and_deploy_release() {
local dpkg_opts=""
[[ "${DPKG_FORCE_CONFOLD:-}" == "1" ]] && dpkg_opts="-o Dpkg::Options::=--force-confold"
[[ "${DPKG_FORCE_CONFNEW:-}" == "1" ]] && dpkg_opts="-o Dpkg::Options::=--force-confnew"
# SYSTEMD_OFFLINE skips the package's own service start: restart what ran, start what a fresh install enabled.
local deb_pkg deb_fresh="" unit
local -a deb_was_active=()
deb_pkg="$(dpkg-deb -f "$tmpdir/$filename" Package 2>/dev/null)"
if [[ -n "$deb_pkg" ]]; then
if dpkg -s "$deb_pkg" >/dev/null 2>&1; then
for unit in $(_forge_deb_units "$deb_pkg"); do
systemctl is-active --quiet "$unit" 2>/dev/null && deb_was_active+=("$unit")
done
else
deb_fresh=1
fi
fi
DEBIAN_FRONTEND=noninteractive SYSTEMD_OFFLINE=1 $STD apt install -y $dpkg_opts "$tmpdir/$filename" || {
SYSTEMD_OFFLINE=1 dpkg -i "$tmpdir/$filename" >"$tmpdir/dpkg.log" 2>&1 || {
_diagnose_deb_failure "$tmpdir/$filename" "$tmpdir/dpkg.log"
_cs_repair_dpkg
return 100
}
}
if [[ -n "$deb_pkg" ]]; then
for unit in $(_forge_deb_units "$deb_pkg"); do
if [[ " ${deb_was_active[*]} " == *" $unit "* ]]; then
systemctl restart "$unit" 2>/dev/null || msg_warn "${unit} did not restart after the ${deb_pkg} update"
elif [[ -n "$deb_fresh" ]] && systemctl is-enabled --quiet "$unit" 2>/dev/null; then
systemctl start "$unit" 2>/dev/null || msg_warn "${unit} did not start after installing ${deb_pkg}"
fi
done
fi
;;

prebuild | singlefile)
Expand Down
78 changes: 78 additions & 0 deletions tests/forge-deb-services.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env bash
set -uo pipefail

CORE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
eval "$(awk '/^(fetch_and_deploy_release|_forge_deb_units|_forge_workdir|_forge_is_script_app|_forge_descriptor|_forge_strip_v|_forge_previous_version)[(][)] [{]/,/^}/' "$CORE_DIR/lib/forge.func")"

if [[ ! -d /run/systemd/system ]]; then
echo "SKIP: no /run/systemd/system on this machine"
exit 0
fi

TEST_DIR="$(mktemp -d)"
trap 'rm -rf -- "$TEST_DIR"' EXIT
export HOME="$TEST_DIR/home"
mkdir -p "$HOME"
LOG="$TEST_DIR/log"
passed=0 failed=0

check() {
if [[ "$3" == "$2" ]]; then
echo "PASS $1"
passed=$((passed + 1))
else
echo "FAIL $1: expected <$2>, got <$3>" >&2
sed 's/^/ /' "$LOG" >&2
failed=$((failed + 1))
fi
}

# shellcheck disable=SC2034 # read by the eval'd helpers
STD=""
jq() { command jq "$@" | tr -d '\r'; }
msg_info() { :; }
msg_ok() { :; }
msg_warn() { echo "warn: $*" >>"$LOG"; }
msg_error() { echo "error: $*" >>"$LOG"; }
_forge_release_json() { printf '{"tag_name":"v2.0.0"}' >"$5"; }
_forge_asset_urls() { echo "https://example.invalid/demo_2.0.0_amd64.deb"; }
curl_download() { : >"$1"; }
apt() { echo "apt $*" >>"$LOG"; }
dpkg-deb() { echo demo; }
dpkg() {
case "$1" in
--print-architecture) echo amd64 ;;
-s) [[ "$INSTALLED" == yes ]] ;;
-L) printf '%s\n' /usr/bin/demo /lib/systemd/system/demo.service \
/lib/systemd/system/demo-worker.service /lib/systemd/system/demo-job@.service ;;
esac
}
systemctl() {
case "$1" in
is-active) [[ " $ACTIVE " == *" $3 "* ]] ;;
is-enabled) [[ " $ENABLED " == *" $3 "* ]] ;;
restart | start) echo "$1 $2" >>"$LOG" ;;
esac
}

deploy() {
: >"$LOG"
rm -f "$HOME"/.demo*
fetch_and_deploy_release github demo owner/demo binary latest "" "demo_*_amd64.deb" >/dev/null 2>&1
grep -E '^(start|restart) ' "$LOG" | sort | tr '\n' ' ' | sed 's/ $//'
}

INSTALLED=no ACTIVE="" ENABLED="demo.service"
check "fresh install starts the enabled unit only" "start demo.service" "$(deploy)"

INSTALLED=yes ACTIVE="demo.service demo-worker.service" ENABLED="demo.service demo-worker.service"
check "upgrade restarts the units that ran" "restart demo-worker.service restart demo.service" "$(deploy)"

INSTALLED=yes ACTIVE="" ENABLED="demo.service"
check "a unit stopped before the update stays stopped" "" "$(deploy)"

INSTALLED=yes ACTIVE="demo.service" ENABLED="demo.service"
check "templates are never touched" "0" "$(deploy >/dev/null; grep -c 'demo-job@' "$LOG")"

echo "${passed} passed, ${failed} failed"
[[ "$failed" -eq 0 ]]
Loading