Shaped after the Livetrail workflow: one job on a project-labelled host runner, preflight checks, rsync from the runner's checkout. rsync rather than a pull in the live directory, so the deploy needs no credentials of its own for git:. The tests run first and gate the rest, .venv and members.json are excluded so the runtime and the learned stereo pair survive, and the last step waits for the panel to answer -- the home page renders from config alone, so it says the app came back up without waiting on the speakers. The unit carries the real paths and user, which the README's sketch of it never did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
3.2 KiB
YAML
98 lines
3.2 KiB
YAML
# runs-on must match the label the runner was registered with -- `heos`
|
|
# here, the way Livetrail uses `livetrail`. A job asking for a label
|
|
# nobody offers sits in the queue rather than failing.
|
|
#
|
|
# The runner has to be in host mode on the machine that serves the panel:
|
|
# it writes into DEPLOY_PATH and restarts the service. See
|
|
# deploy/heos-panel.service for the unit and the one sudoers line the
|
|
# restart needs.
|
|
#
|
|
# DEPLOY_PATH is also where you edit: an rsync --delete lands on top of
|
|
# whatever is sitting there uncommitted, so commit before you push.
|
|
|
|
name: Deploy HEOS panel
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
deploy:
|
|
runs-on: heos
|
|
|
|
env:
|
|
DEPLOY_PATH: /var/www/html/heos
|
|
SERVICE: heos-panel
|
|
PANEL_URL: http://127.0.0.1:5005/ # WEB_PORT in config.py
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Check runner tools
|
|
run: |
|
|
command -v python3
|
|
command -v rsync
|
|
command -v curl
|
|
|
|
- name: Check deploy path
|
|
run: |
|
|
test -d "$DEPLOY_PATH"
|
|
test -w "$DEPLOY_PATH"
|
|
|
|
- name: Check the restart is allowed without a password
|
|
run: sudo -n systemctl is-active "$SERVICE" || true
|
|
|
|
# A throwaway virtualenv in the workspace: the one under
|
|
# $DEPLOY_PATH/.venv is what the running panel imports from, and a
|
|
# test run has no business touching it.
|
|
- name: Install dependencies
|
|
run: |
|
|
python3 -m venv .venv-ci
|
|
.venv-ci/bin/pip install --quiet --upgrade pip
|
|
.venv-ci/bin/pip install --quiet -r requirements.txt
|
|
|
|
# Runs against the fake HEOS and AVR servers in tests/fakes.py, so it
|
|
# needs no speakers and touches nothing on the network.
|
|
- name: Run tests
|
|
run: .venv-ci/bin/python -m unittest discover -s tests -t . --verbose
|
|
|
|
- name: Deploy to production
|
|
run: |
|
|
rsync -azc --no-times --delete \
|
|
--exclude "/.git/" \
|
|
--exclude "/.gitea/" \
|
|
--exclude "/.venv/" \
|
|
--exclude "/.venv-ci/" \
|
|
--exclude "/members.json" \
|
|
--exclude "__pycache__/" \
|
|
./ "$DEPLOY_PATH/"
|
|
|
|
# members.json is the stereo pair's learned membership and .venv is
|
|
# the runtime -- both are excluded above, so --delete leaves them be.
|
|
|
|
- name: Install runtime dependencies
|
|
run: |
|
|
test -d "$DEPLOY_PATH/.venv" || python3 -m venv "$DEPLOY_PATH/.venv"
|
|
"$DEPLOY_PATH/.venv/bin/pip" install --quiet -r "$DEPLOY_PATH/requirements.txt"
|
|
|
|
- name: Restart
|
|
run: sudo systemctl restart "$SERVICE"
|
|
|
|
- name: Wait for the panel to answer
|
|
run: |
|
|
# The home page renders from config alone, so this proves the app
|
|
# came back up without waiting on the speakers to reply.
|
|
for attempt in $(seq 1 20); do
|
|
if curl -fsS -o /dev/null "$PANEL_URL"; then
|
|
echo "panel is up after ${attempt}s"
|
|
exit 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
echo "panel did not come back -- last of its log:"
|
|
sudo systemctl status "$SERVICE" --no-pager --lines 30 || true
|
|
exit 1
|