diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index eeedb2a..83742dc 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -7,6 +7,11 @@ # deploy/heos-panel.service for the unit and the one sudoers line the # restart needs. # +# Every step here is plain shell, on purpose. actions/checkout is a +# JavaScript action, and a host-mode runner can only run those if node is +# on its PATH -- swapping the clone below back to `uses: actions/checkout` +# brings back "Cannot find: node in PATH" on a runner without it. +# # DEPLOY_PATH is also where you edit: an rsync --delete lands on top of # whatever is sitting there uncommitted, so commit before you push. @@ -26,13 +31,12 @@ jobs: DEPLOY_PATH: /var/www/html/heos SERVICE: heos-panel PANEL_URL: http://127.0.0.1:5005/ # WEB_PORT in config.py + SRC: src # the clone, inside the workspace steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Check runner tools run: | + command -v git command -v python3 command -v rsync command -v curl @@ -45,10 +49,24 @@ jobs: - name: Check the restart is allowed without a password run: sudo -n systemctl is-active "$SERVICE" || true + # A shallow clone of the pushed branch, taking the remote from the + # live checkout so there is no URL or token written down here. It + # works because the runner runs as the user that owns that checkout, + # which is the same reason it can write to DEPLOY_PATH at all. + - name: Checkout + run: | + rm -rf "$SRC" + git init --quiet "$SRC" + git -C "$SRC" remote add origin "$(git -C "$DEPLOY_PATH" remote get-url origin)" + git -C "$SRC" fetch --quiet --depth 1 origin "${GITHUB_REF_NAME:-main}" + git -C "$SRC" checkout --quiet FETCH_HEAD + git -C "$SRC" --no-pager log -1 --oneline + # 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 + working-directory: src run: | python3 -m venv .venv-ci .venv-ci/bin/pip install --quiet --upgrade pip @@ -57,9 +75,11 @@ jobs: # 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 + working-directory: src run: .venv-ci/bin/python -m unittest discover -s tests -t . --verbose - name: Deploy to production + working-directory: src run: | rsync -azc --no-times --delete \ --exclude "/.git/" \ diff --git a/README.md b/README.md index 10c6448..0043c97 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,15 @@ restarts the service and waits for the panel to answer again. It needs a runner **in host mode on the machine that serves the panel**, registered with the label `heos` (`runs-on:` must match, or the job queues -forever), running as the user that owns the directory. Restarting needs -one sudoers line: +forever), running as the user that owns the directory. + +Every step is plain shell. `actions/checkout` is a JavaScript action, and a +host-mode runner can only run those with `node` on its PATH — swapping the +clone back for it brings back `Cannot find: node in PATH`. The clone takes +its URL from the live checkout's own remote, so no URL or token is written +down here. + +Restarting needs one sudoers line: ```bash echo 'franzz ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart heos-panel' \