diff --git a/.gitea/workflows/check.yml b/.gitea/workflows/check.yml index 7f5c728..c1f0605 100644 --- a/.gitea/workflows/check.yml +++ b/.gitea/workflows/check.yml @@ -8,20 +8,16 @@ on: jobs: check: runs-on: ubuntu-latest + container: + image: daily-blackout-check-runner:latest + env: + PYTHONPATH: src steps: - name: Check out repository uses: https://gitea.com/actions/checkout@v4 with: fetch-depth: 0 - - name: Set up Python - uses: https://gitea.com/actions/setup-python@v5 - with: - python-version: "3.13" - - - name: Install project - run: python -m pip install . - - name: Check outages and persist state env: BARGHEMAN_TOKEN: ${{ secrets.BARGHEMAN_TOKEN }} diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml index ba5fb66..07d3ee1 100644 --- a/.gitea/workflows/test.yml +++ b/.gitea/workflows/test.yml @@ -10,18 +10,14 @@ on: jobs: test: runs-on: ubuntu-latest + container: + image: daily-blackout-check-runner:latest + env: + PYTHONPATH: src steps: - name: Check out repository uses: https://gitea.com/actions/checkout@v4 - - name: Set up Python - uses: https://gitea.com/actions/setup-python@v5 - with: - python-version: "3.13" - - - name: Install project - run: python -m pip install -e '.[test]' - - name: Lint run: ruff check . diff --git a/README.md b/README.md index 8a7e585..2b2e0db 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ state is stored in `state/outages.json` and committed back to this repository. ## Local setup -Python 3.11 or newer is required. CI uses Python 3.13. +Python 3.11 or newer is required. The Gitea runner image uses Debian's Python 3.11. ```sh python -m venv .venv @@ -62,17 +62,40 @@ Shell and Gitea-provided variables take precedence over `.env`. ## Gitea deployment This repository targets Gitea 1.25.x and a Docker-based runner advertising the -`ubuntu-latest` label. The runner needs outbound access to the Gitea instance, -`gitea.com`, PyPI, SAAPA, and EitaaYar. +`ubuntu-latest` label. Both workflows run inside the locally built +`daily-blackout-check-runner:latest` image. It contains Node for the checkout +action plus Python, Git, timezone data, application dependencies, pytest, and +Ruff. Scheduled jobs therefore do not install Python or download Python packages. -1. Enable Actions in the repository settings. -2. Confirm an online runner advertises `ubuntu-latest`. -3. Add these repository Actions secrets: +Build the image on the Docker host used by `act_runner`: + +```sh +cd /path/to/daily-blackout-check +docker build \ + --tag daily-blackout-check-runner:latest \ + runner-image +docker image inspect daily-blackout-check-runner:latest >/dev/null +``` + +Only `runner-image/` is sent as the Docker build context, so local secrets and +outage state never enter the build context or image. + +The image is local rather than registry-hosted, matching the deployment pattern +used by `mahak-api-docs`. Build it on every runner host that can claim this job. +Rebuild it whenever `runner-image/Dockerfile`, `runner-image/requirements.lock`, +or dependency declarations in `pyproject.toml` change. The image build requires +Docker Hub and PyPI access; normal workflow runs only need the Gitea instance, +`gitea.com`, SAAPA, and EitaaYar. + +1. Build `daily-blackout-check-runner:latest` on the runner's Docker host. +2. Enable Actions in the repository settings. +3. Confirm an online Docker runner advertises `ubuntu-latest`. +4. Add these repository Actions secrets: `BARGHEMAN_TOKEN`, `EITAAYAR_TOKEN`, `CHAT_ID`, and `BILL_IDS`. -4. Run the test workflow manually. -5. Run **Hourly blackout check** manually once and inspect the notification and +5. Run the test workflow manually. +6. Run **Hourly blackout check** manually once and inspect the notification and resulting state commit. -6. Leave the `@hourly` schedule enabled. +7. Leave the `@hourly` schedule enabled. The workflow uses fully qualified `https://gitea.com/actions/...` actions rather than resolving actions through GitHub. Gitea 1.25 ignores workflow `permissions` @@ -81,6 +104,11 @@ Its checkout credential must retain the default ability to push to the current repository. Scheduled jobs should not be manually overlapped; in the rare event of a push race, the job fails and unsaved notices may be repeated on the next run. +If a workflow tries to pull the local image instead of using it, ensure the image +exists in the same Docker daemon used by `act_runner` and set +`container.force_pull: false` in the runner's generated `config.yaml`, then +restart the runner. + ## Development ```sh diff --git a/runner-image/Dockerfile b/runner-image/Dockerfile new file mode 100644 index 0000000..abd4f23 --- /dev/null +++ b/runner-image/Dockerfile @@ -0,0 +1,26 @@ +FROM node:20-bookworm + +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + ca-certificates \ + git \ + python3 \ + python3-pip \ + python3-venv \ + tzdata && \ + rm -rf /var/lib/apt/lists/* + +COPY requirements.lock /tmp/requirements.lock + +RUN python3 -m venv /opt/blackout-venv && \ + /opt/blackout-venv/bin/pip install --no-cache-dir -r /tmp/requirements.lock && \ + /opt/blackout-venv/bin/python -c "import dotenv, jdatetime, requests" && \ + /opt/blackout-venv/bin/pytest --version && \ + /opt/blackout-venv/bin/ruff --version && \ + rm /tmp/requirements.lock + +ENV PATH="/opt/blackout-venv/bin:$PATH" \ + PYTHONDONTWRITEBYTECODE="1" \ + PYTHONUNBUFFERED="1" + +CMD ["bash"] diff --git a/runner-image/requirements.lock b/runner-image/requirements.lock new file mode 100644 index 0000000..a4eaac6 --- /dev/null +++ b/runner-image/requirements.lock @@ -0,0 +1,14 @@ +certifi==2026.6.17 +charset-normalizer==3.4.9 +idna==3.18 +iniconfig==2.3.0 +jalali_core==1.0.0 +jdatetime==6.0.1 +packaging==26.2 +pluggy==1.6.0 +Pygments==2.20.0 +pytest==9.1.1 +python-dotenv==1.2.2 +requests==2.34.2 +ruff==0.15.22 +urllib3==2.7.0