155 lines
8.1 KiB
Markdown
155 lines
8.1 KiB
Markdown
# Gitea CI
|
|
|
|
This repository targets **Gitea 1.23.8**. The workflow is in
|
|
`.gitea/workflows/ci.yaml`; it runs on pushes, pull requests, and manual dispatch.
|
|
It tests and publishes images on master. Manual **Run app** dispatch runs a
|
|
selected image over restricted SSH; see [SSH_RUN.md](SSH_RUN.md) for setup.
|
|
No live scraping, production migration, or production DB access occurs in CI.
|
|
|
|
## What Runs
|
|
|
|
One Docker-backed job, selected by the runner label `python-ci`, performs:
|
|
|
|
1. Checkout using a commit-pinned action, without persisting checkout credentials.
|
|
2. Install uv 0.9.3 and Python 3.13, then `uv sync --locked --dev`.
|
|
3. Run Ruff's correctness-focused checks over `src` and `tests`.
|
|
4. Run the full unittest suite, including integration tests against a fresh
|
|
PostgreSQL 17 service named `postgres` and database `car_tracker_test`, matching
|
|
the homelab's PostgreSQL major version.
|
|
5. Build the source distribution and wheel, install that wheel in an independent
|
|
environment, and verify that its SQL migrations are packaged.
|
|
|
|
The service password `ci-test-only` is deliberately public and only for the
|
|
ephemeral test database. No database port is published on the runner host. Never
|
|
replace `TEST_DATABASE_URL` with a production connection string: the integration
|
|
tests truncate their test tables. No browser installation or live scraping occurs.
|
|
No raw data, browser profiles, password files, or laptop environment is mounted.
|
|
|
|
The job image is `node:22-bookworm` so JavaScript actions have Node, Git, and the
|
|
basic Linux tools they need; uv supplies Python. The image is not your application
|
|
deployment image. Both action references use explicit GitHub URLs and commit SHAs.
|
|
The setup-uv action receives an empty `github-token`, so the Gitea job token is not
|
|
sent to GitHub's release API. Caching and problem matchers are disabled for this
|
|
first Gitea setup. PostgreSQL and Node images track their declared version tags;
|
|
action commits, uv, and the Python dependency lockfile are explicitly pinned.
|
|
|
|
Gitea 1.23 ignores several GitHub workflow keys, including job-level
|
|
`timeout-minutes`, `permissions`, and `concurrency`; the workflow does not pretend
|
|
they provide protections. Runner configuration enforces capacity 1 and a 45-minute
|
|
job timeout; the test command also has a 10-minute timeout.
|
|
|
|
## Enable Repository Actions
|
|
|
|
In Gitea, open the `tonio/car-tracker` repository's **Settings** and enable
|
|
**Repository Actions**. Actions are enabled globally by default since Gitea 1.21,
|
|
but disabled for repositories by default. If the repository option is unavailable,
|
|
check the instance's `[actions] ENABLED` setting and your permissions.
|
|
|
|
Pushing a workflow is not enough: a runner with the matching label must be online.
|
|
Until then, runs can remain waiting. If Actions were disabled when the workflow
|
|
was pushed, enable them and use the manual run button afterward.
|
|
|
|
## Register A Runner
|
|
|
|
Use a dedicated Linux CI VM with Docker and Docker Compose, preferably separate
|
|
from the Gitea and PostgreSQL hosts. A laptop can host a temporary runner, but jobs
|
|
will stop being serviced when it sleeps or disconnects. The included configuration
|
|
uses `gitea/act_runner:0.2.13`, with the configuration format verified from that
|
|
release. Do not substitute the newer renamed runner without checking compatibility
|
|
with your Gitea version.
|
|
|
|
The runner daemon needs Docker socket access, which is effectively root access to
|
|
the CI host. Do not put production database credentials, backups, or raw listing
|
|
data on that host. Job containers now receive the socket for builds, but arbitrary
|
|
workflow host bind mounts are not allowlisted. This does not make self-hosted execution
|
|
safe for arbitrary hostile workflows. Register at repository scope, accept only
|
|
trusted contributors/workflows, and review fork pull requests before allowing them
|
|
to run. Runner and server updates should be planned independently of this initial
|
|
setup; Gitea 1.23.8 is an older release.
|
|
|
|
On the CI host, check out this repository, then run from its root:
|
|
|
|
```sh
|
|
docker compose -f ops/ci-runner/compose.yaml pull
|
|
docker compose -f ops/ci-runner/compose.yaml run --rm runner \
|
|
--config /config.yaml register
|
|
```
|
|
|
|
Registration is interactive, so a registration token is not placed in shell
|
|
arguments or a committed environment file. Obtain a **repository-scoped** token
|
|
from `tonio/car-tracker` -> **Settings -> Actions -> Runners**. Enter:
|
|
|
|
| Prompt | Value |
|
|
| --- | --- |
|
|
| Instance URL | Your Gitea **HTTP(S) web URL**, including its port if needed |
|
|
| Registration token | The repository token, entered locally; do not send it in chat |
|
|
| Runner name | For example `gitea-runner` (the name does not affect job routing) |
|
|
| Labels | `python-ci:docker://node:22-bookworm` |
|
|
|
|
The instance URL is **not** the Git SSH URL ending in port 2222. It must resolve
|
|
and be reachable from both the runner container and its job containers. Avoid
|
|
`localhost`, which would refer to a container. If using a VPN-only hostname,
|
|
verify DNS and routing inside Docker as well as on the CI host. HTTPS certificate
|
|
verification remains enabled; configure trust for private certificates rather
|
|
than disabling it.
|
|
|
|
Registration writes credentials to `ops/ci-runner/data/.runner` via the `./data` bind.
|
|
The deployed copy on the new VM is `~/containers/gitea-runner/data/.runner`.
|
|
Keep this directory private and outside Git. No registration token is needed in Compose's
|
|
environment. Start the registered daemon:
|
|
|
|
```sh
|
|
docker compose -f ops/ci-runner/compose.yaml up -d
|
|
docker compose -f ops/ci-runner/compose.yaml logs --tail=100 runner
|
|
```
|
|
|
|
Confirm in Gitea that the runner is online and advertises **`python-ci`**, then
|
|
trigger the CI workflow. The runner needs outbound access to your Gitea web URL,
|
|
GitHub/action releases, PyPI/Python downloads, and the container registry. It does
|
|
not need your application PostgreSQL credentials or an HBA rule for that database.
|
|
Restrict CI-host network access to production services where practical.
|
|
|
|
Do not run `docker compose down -v` unless you intend to erase runner registration.
|
|
Normal container recreation preserves the registration directory.
|
|
|
|
## First Run Checks
|
|
|
|
- A job stuck waiting usually means Actions are disabled, the runner is offline,
|
|
or its label does not match `python-ci`.
|
|
- Checkout failures often mean job containers cannot resolve/reach Gitea's web URL
|
|
or trust its TLS certificate. Successful Git SSH access from the laptop does not
|
|
prove HTTP(S) checkout works from a Docker container.
|
|
- `postgres` must resolve inside the job's Docker network. Leave `container.network`
|
|
empty so act_runner creates the service network; do not use host networking.
|
|
- The integration tests must execute, not be skipped. `TEST_DATABASE_URL` is set
|
|
in the workflow and points only to the disposable service.
|
|
- Caching is deliberately absent, so no cache-server ports or credentials are needed.
|
|
|
|
The workflow was executed locally using `act_runner 0.2.13` against an archive of
|
|
the staged source, with no laptop credentials or raw snapshots included. Linting,
|
|
all 82 tests (including PostgreSQL integration tests), the build, and installed-wheel
|
|
migration checks passed. Local execution substituted the source archive for remote
|
|
checkout; Gitea HTTP(S) checkout and server-triggered execution still need verification
|
|
after a runner is registered and the repository's Actions feature is enabled.
|
|
|
|
The suite was subsequently rerun against disposable PostgreSQL 17.11: all 82 tests
|
|
passed, including all database integration tests. CI now uses `postgres:17` to match
|
|
the homelab's major version.
|
|
|
|
## Local Checks
|
|
|
|
```sh
|
|
uv sync --locked --dev
|
|
uv run --locked ruff check src tests
|
|
uv run --locked python -m unittest discover -s tests -v
|
|
uv build --no-sources
|
|
```
|
|
|
|
Without `TEST_DATABASE_URL`, database integration tests are skipped locally. Use
|
|
the [disposable PostgreSQL instructions](POSTGRESQL.md#tests) to run them, never the
|
|
homelab application database. Keep `.env`, `.pgpass`, `.runner`, and `data/` out of Git.
|
|
|
|
References: [Gitea 1.23 quick start](https://docs.gitea.com/1.23/usage/actions/quickstart),
|
|
[runner setup](https://docs.gitea.com/1.23/usage/actions/act-runner), and
|
|
[compatibility differences](https://docs.gitea.com/1.23/usage/actions/comparison).
|