126 plikow (md, yaml, sh, py) odwolywalo sie do sciezek sprzed migracji.
15 markdown-linkow [..](..) -> policzona sciezka WZGLEDNA wobec pliku
odsylajacego (wczesniej czesc z nich byla repo-root-relative i nie
rozwiazywala sie z katalogu, w ktorym lezala)
200 odwolan tekstowych (backticki, proza, yaml, importy w kodzie)
-> nowa sciezka repo-root-relative, zgodnie z konwencja repo
5 linkow rodzenstwa (gole nazwy plikow, np. "](DEPLOY.md)") — dzialaly
tylko w starym katalogu; przeliczone recznie
Objete m.in.: CLAUDE.md (scripts/onboard/README.md -> kb/runbooks/
node-onboarding-tool.md, docs/backlog.md -> kb/phases/backlog.md),
README.md, .claude/skills/, 20 session logow, kod jobow.
Ostatnie 5 odwolan pochodzi z tresci wciagnietej rebasem z origin/master
(session log 2026-07-31, override node-agenta na SOLARII, dwie pozycje
backlogu) — wskazywaly na docs/incidents/, docs/kb/modules/ i
services/narty27/README.md sprzed migracji.
Dodany wzajemny link miedzy kb/services/control-plane.md (stub kodu)
a kb/subsystems/control-plane.md (opis, deprecated) — dwa dokumenty o tym
samym systemie, latwe do pomylenia.
Weryfikacja na 790 plikach: 0 odwolan do starych sciezek,
0 martwych linkow markdown. Lint OKF: 190/190 plikow ZGODNE.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
97 lines
3.5 KiB
Bash
Executable file
97 lines
3.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Write path: repo -> HA instance, for the "api" adapter only (see
|
|
# kb/decisions/ha-configs-as-code.md, "Deploy path: adapter per instance",
|
|
# "Sync model", "Validation gate").
|
|
#
|
|
# Scope: automations/scripts/scenes only. Dashboards and helpers are
|
|
# WebSocket-only (scripts/ha/lib/ha_ws.py has no mutating command,
|
|
# deliberately) — writing those is a separate, not-yet-built task.
|
|
#
|
|
# Hard sequence enforced in lib/deploy_api.py, no shortcuts: DRIFT-CHECK ->
|
|
# VALIDATE (local + live check_config) -> WRITE (per object) -> VERIFY (per
|
|
# object). Any drift or validation failure aborts before a single mutating
|
|
# call is made. --dry-run runs the same DRIFT-CHECK/VALIDATE steps (both
|
|
# read-only in effect) and stops before WRITE/VERIFY.
|
|
#
|
|
# Instances with status != "active" (e.g. ken-legacy: archived, chelsty-ha:
|
|
# offline) or adapter != "api" are refused unconditionally — see
|
|
# instances.yaml and DESIGN.md's "Incident log" for why ken-legacy must
|
|
# never be a deploy target again.
|
|
#
|
|
# Usage: deploy.sh <instance> [--dry-run] [file...]
|
|
# no file args -> every automations/scripts/scenes file currently in
|
|
# services/home-assistant/config/<instance>/
|
|
# file args -> only those objects (path as given, repo-root-relative,
|
|
# or config-dir-relative all accepted)
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SERVICE_DIR="$(cd "$SCRIPT_DIR/../../services/home-assistant" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
INSTANCES_FILE="$SERVICE_DIR/instances.yaml"
|
|
|
|
usage() {
|
|
echo "usage: $0 <instance> [--dry-run] [file...]" >&2
|
|
}
|
|
|
|
if [[ $# -lt 1 ]]; then
|
|
usage
|
|
exit 2
|
|
fi
|
|
|
|
INSTANCE="$1"
|
|
shift
|
|
|
|
DRY_RUN=0
|
|
FILE_ARGS=()
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--dry-run) DRY_RUN=1 ;;
|
|
--) ;;
|
|
*) FILE_ARGS+=("$arg") ;;
|
|
esac
|
|
done
|
|
|
|
if [[ ! -f "$INSTANCES_FILE" ]]; then
|
|
echo "error: instances file not found: $INSTANCES_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
INSTANCE_CONFIG_OUTPUT="$(python3 "$SCRIPT_DIR/lib/instance_config.py" "$INSTANCES_FILE" "$INSTANCE")" || exit 1
|
|
eval "$INSTANCE_CONFIG_OUTPUT"
|
|
|
|
if [[ "$HA_STATUS" != "active" ]]; then
|
|
echo "error: instance '$INSTANCE' has status='$HA_STATUS', not 'active' — deploy.sh refuses" >&2
|
|
echo " non-active instances unconditionally, no override flag (see instances.yaml)." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$HA_ADAPTER" != "api" ]]; then
|
|
echo "error: instance '$INSTANCE' uses adapter='$HA_ADAPTER' — deploy.sh only implements" >&2
|
|
echo " the 'api' write path (see DESIGN.md, 'Deploy path: adapter per instance')." >&2
|
|
exit 1
|
|
fi
|
|
|
|
api_token_file="${HA_TOKEN_PATH/#\~/$HOME}"
|
|
if [[ -z "$HA_TOKEN_PATH" || ! -f "$api_token_file" ]]; then
|
|
echo "error: instance '$INSTANCE' has no token at '${api_token_file:-<unset>}' — deploy.sh" >&2
|
|
echo " has no fallback without a deploy_agent long-lived access token (see" >&2
|
|
echo " DESIGN.md, 'Tokens')." >&2
|
|
exit 1
|
|
fi
|
|
|
|
CONFIG_DIR="$SERVICE_DIR/config/$INSTANCE"
|
|
CONFIG_RELPATH="services/home-assistant/config/$INSTANCE"
|
|
|
|
if [[ ! -d "$CONFIG_DIR" ]]; then
|
|
echo "error: no config/$INSTANCE/ directory — run scripts/ha/import.sh $INSTANCE at least" >&2
|
|
echo " once first, so there is a last-known snapshot to drift-check against." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "== ha deploy: instance=$INSTANCE adapter=$HA_ADAPTER dry_run=$DRY_RUN ==" >&2
|
|
|
|
python3 "$SCRIPT_DIR/lib/deploy_api.py" \
|
|
"$HA_BASE_URL" "$api_token_file" "$REPO_ROOT" "$CONFIG_DIR" "$CONFIG_RELPATH" "$INSTANCE" "$DRY_RUN" \
|
|
"${FILE_ARGS[@]}"
|