fix(deploy): report what enable actually did, and arm the tier's timers
Two lies in the unit loop, both reported as success: - `systemctl --user enable live-sync.service` fails on every deploy — the file has no [Install] section, because live-sync.timer is what arms it. The result was swallowed by `|| true` and the tool printed ENABLE anyway, so the line an operator reads after a rebuild was false on every box, on the repo's own heartbeat. The [Install] section is readable from the file being deployed, so the tool now checks it and prints INERT with the reason instead of making a call that cannot succeed; a real enable failure prints INERT too. - The loop walked *.service only. live-sync.timer was never enabled by anything, so a rebuilt box got the heartbeat and no schedule for it. Timers are walked now; a timer has no ExecStart, so the "does this unit belong on this box" test runs against the service it activates. The systemctl stub models systemd's refusal (no [Install] section -> non-zero), which is what makes the new tests red against the old loop; both new tests were run red first, and the five existing unit tests still pin #44's semantics. Refs #60
This commit is contained in:
1 parent
812be6a0a6
commit
f3ce42eb80
3 files changed
+109
-17
No files matched your search
+59
-1
@@ -37,7 +37,22 @@ if [ "$2" = is-enabled ]; then
|
||||
printf '%s\n' "$state"
|
||||
case "$state" in disabled | "") exit 1 ;; *) exit 0 ;; esac
|
||||
fi
|
||||
exit 0
|
||||
if [ "$2" = enable ]; then
|
||||
# Modelled, not stubbed flat: systemd refuses to enable a unit whose file has no [Install]
|
||||
# section, and the deployed file is what it reads. A stub that always says yes hides the
|
||||
# one case this repo actually ships (live-sync.service is driven by its timer).
|
||||
target=""
|
||||
for a in "$@"; do
|
||||
case "$a" in
|
||||
*.service | *.timer | *.socket) target="$a" ;;
|
||||
esac
|
||||
done
|
||||
file="$HOME/.config/systemd/user/${target##*/}"
|
||||
if [ -e "$file" ] && ! grep -q '^\[Install\]' "$file"; then
|
||||
printf 'The unit files have no installation config (WantedBy=, RequiredBy=, Also= settings in the [Install] section). This means they are not meant to be enabled using this command.\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
STUB
|
||||
chmod +x "$TEST_TMP/bin/systemctl"
|
||||
export PATH="$TEST_TMP/bin:$PATH"
|
||||
@@ -57,6 +72,21 @@ systemd_unit() {
|
||||
> "$REPO/dotfiles/systemd-user/.config/systemd/user/$1"
|
||||
}
|
||||
|
||||
# systemd_unit_no_install <name> <ExecStart> — a unit nothing can enable (live-sync.service:
|
||||
# it is pulled in by live-sync.timer, so it carries no [Install] section on purpose).
|
||||
systemd_unit_no_install() {
|
||||
mkdir -p "$REPO/dotfiles/systemd-user/.config/systemd/user"
|
||||
printf '[Unit]\nDescription=%s\n[Service]\nType=oneshot\nExecStart=%s\n' "$1" "$2" \
|
||||
> "$REPO/dotfiles/systemd-user/.config/systemd/user/$1"
|
||||
}
|
||||
|
||||
# systemd_timer <name> <service-name> — a schedule; it has no ExecStart of its own.
|
||||
systemd_timer() {
|
||||
mkdir -p "$REPO/dotfiles/systemd-user/.config/systemd/user"
|
||||
printf '[Unit]\nDescription=%s\n[Timer]\nOnCalendar=hourly\nPersistent=true\n[Install]\nWantedBy=timers.target\n' "$1" \
|
||||
> "$REPO/dotfiles/systemd-user/.config/systemd/user/$1"
|
||||
}
|
||||
|
||||
@test "generated theme output is never adopted into a symlink" {
|
||||
repo_file "ghostty/.config/ghostty/themes/noctalia" 'background = "#f43841"'
|
||||
live_file "$HOME/.config/ghostty/themes/noctalia" 'background = "#f43841"'
|
||||
@@ -152,3 +182,31 @@ systemd_unit() {
|
||||
grep -q 'systemctl --user enable heartbeat.service' "$STUB_LOG"
|
||||
! grep -q -- '--now' "$STUB_LOG"
|
||||
}
|
||||
|
||||
@test "a unit nothing can enable is reported as what it is, never as ENABLE" {
|
||||
# `systemctl --user enable live-sync.service` fails on every deploy: the file has no
|
||||
# [Install] section (its timer arms it), and systemd says so with a non-zero exit. The
|
||||
# deploy swallowed that and printed ENABLE, so the one line the operator reads to learn
|
||||
# what a rebuild armed was false on every box, on the repo's own heartbeat.
|
||||
systemd_unit_no_install heartbeat.service /bin/sh
|
||||
printf 'linked\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"heartbeat.service"*"[Install]"* ]]
|
||||
[[ "$output" != *"ENABLE heartbeat.service"* ]]
|
||||
# No futile call: the section is readable from the file being deployed.
|
||||
! grep -q 'systemctl --user enable heartbeat.service' "$STUB_LOG"
|
||||
}
|
||||
|
||||
@test "a timer in the tier is armed, because a service on its own has no schedule" {
|
||||
# The loop walked *.service only. On a rebuilt box live-sync.service is deployed and the
|
||||
# timer is never enabled, so the heartbeat that commits machine state simply does not run
|
||||
# — and the deploy report says nothing about it.
|
||||
systemd_unit heartbeat.service /bin/sh
|
||||
systemd_timer heartbeat.timer heartbeat.service
|
||||
printf 'disabled\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *"SKIP heartbeat.timer"* ]]
|
||||
grep -q 'systemctl --user enable --now heartbeat.timer' "$STUB_LOG"
|
||||
}
|
||||
Reference in new issue
Block a user