Add a Gitea Actions test-status badge plus a short README "CI" section covering how to read the check and what to do when it's red. Capture the (out-of-tree) branch-protection rule on `main` in docs/ci.md so the gate that requires the test check is reproducible from the repo alone — covers both the Gitea UI path and the equivalent API call. Refs: PRD 0002 Assisted-by: Claude Code
2.9 KiB
CI
The test workflow lives at .gitea/workflows/test.yml.
It runs tests/run_tests.py (full suite — unit + integration) on:
- every push to a branch with an open pull request, and
- every push to
main.
Integration tests need Docker on the runner; they skip cleanly via
tests/_docker.skip_unless_docker when no daemon is reachable.
Branch protection on main
Branch protection is not captured in tree — Gitea applies it via the repo settings UI / API, not a checked-in config file. Reproducing the rule on a fresh clone or migration therefore means re-applying the same setting through one of the two paths below.
Via the Gitea UI
- Go to the repo on
gitea.dideric.is. - Settings → Branches → Branch protection rules → Add rule.
- Branch name pattern:
main. - Enable Enable Status Check and select the check named
test / run tests/run_tests.py(the workflow's job display name). The check has to have run at least once on the repo for Gitea to list it; push a no-op commit on a feature branch first if needed. - (Recommended) Also enable Require pull request before merging
so changes to
mainalways go through a PR — otherwise a direct push tomainbypasses the status check entirely. - Save.
After saving, open a PR. The "Merge" button should be disabled until the test check is green.
Via the Gitea API
Equivalent call (requires an admin token in $GITEA_TOKEN):
curl -X POST \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
https://gitea.dideric.is/api/v1/repos/didericis/claude-bottle/branch_protections \
-d '{
"rule_name": "main",
"enable_status_check": true,
"status_check_contexts": ["test / run tests/run_tests.py"],
"required_approvals": 0,
"block_on_outdated_branch": false
}'
The exact field for the check name is
status_check_contexts (an array of glob patterns). The Gitea
Actions check appears under
<workflow-name> / <job-name> — here test / run tests/run_tests.py.
Confirm the actual rendered context string in Repo → Actions →
→ Job summary before pasting into the API call; Gitea
versions occasionally tweak the formatting and a typo here silently
matches no checks (rule loads, but never blocks).
To inspect the live rule:
curl -H "Authorization: token $GITEA_TOKEN" \
https://gitea.dideric.is/api/v1/repos/didericis/claude-bottle/branch_protections
Verifying the gate
Once the rule is in place, prove it works once with a deliberately-failing test on a throwaway branch:
- Create a branch (
gate-test-DELETEME), add a test that fails (e.g.self.assertTrue(False)), push, open a PR. - Wait for the check to go red. Confirm the "Merge" button is disabled / shows the unmet status check.
- Close the PR and delete the branch. Do not merge.
This is a one-time check after applying the rule, not a recurring exercise.