- Shell 98.8%
- Python 1.2%
| .forgejo | ||
| ISSUE_TEMPLATE | ||
| scripts | ||
| src | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| pull_request_template.md | ||
| pyproject.toml | ||
| README.md | ||
| xegames.config.yml | ||
template-python
Template for XeplosionGames Python projects. Includes ruff formatting and linting, pytest testing, virtual environment management, and systemd service deployment to hub via CI/CD workflows.
Creating a repo from this template
- Click Use this template on Forgejo
- Update
pyproject.toml— setnameanddescription - Follow the setup checklist below
Setup checklist
- Set
RELEASE_TOKENsecret in Settings → Secrets - Update
nameanddescriptioninpyproject.toml - Set
SERVICE_NAMEandDEPLOY_PATHinscripts/service-start.shandscripts/service-stop.sh - Set
healthcheck.endpointinxegames.config.ymlif service exposes HTTP - Create the service directory on hub:
sudo mkdir -p /opt/
sudo chown cicd:cicd /opt/
- Clone repo on hub as
cicduser:
sudo -u cicd git clone git@git.xegames.online:XeplosionGames/.git /opt/
- Create the systemd service file (see below)
- Add sudoers entry on hub for service restart
- Run
create-project.shfromXeplosionGames/.forgejoto seed project board - Push to
mainand verify CI passes - Enable
notify.zulip: trueonce service is stable
Virtual environment
This template uses Python's built-in venv for dependency isolation.
The venv lives at <DEPLOY_PATH>/venv/ on the server and is created
automatically by service-start.sh on first deploy.
Dependencies are defined in pyproject.toml:
[project.dependencies]— runtime dependencies[project.optional-dependencies.dev]— dev/test dependencies (ruff, pytest)
To set up locally:
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install -e ".[dev]"
Systemd service
Python services run via systemd using the venv Python directly — no shell
activation needed. Create a service file at /etc/systemd/system/<service>.service
on hub:
[Unit]
Description=
After=network.target
[Service]
Type=simple
User=
WorkingDirectory=/opt/
ExecStart=/opt//venv/bin/python -m
Restart=always
RestartSec=5
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target
Then enable and start:
sudo systemctl daemon-reload
sudo systemctl enable
sudo systemctl start
Add a sudoers entry for the cicd user:
cicd ALL=(ALL) NOPASSWD: /bin/systemctl restart
cicd ALL=(ALL) NOPASSWD: /bin/systemctl stop
Code style
This repo uses ruff for both formatting
and linting, configured via pyproject.toml.
To check locally:
ruff format --check .
ruff check .
To fix locally:
ruff format .
ruff check --fix .
Conventions
| Rule | Value |
|---|---|
| Indentation | 4 spaces |
| Quotes | Double quotes |
| Line length | 100 characters |
| Line endings | LF |
| Import sorting | Enforced via ruff I rules |
Testing
Tests live in tests/ and use pytest. Add test files following the
test_*.py naming convention.
To run tests locally:
pytest
To run with coverage:
pytest --cov=src --cov-report=term-missing
Workflows
| Workflow | Trigger | Purpose |
|---|---|---|
ci-python.yml |
Every push / PR | Format check + lint + pytest |
deploy-production.yml |
Push to main |
Deploy to hub, setup venv, restart service |
deploy-test.yml |
Push to dev |
Deploy to test environment (if enabled) |
rollback.yml |
Manual / auto | Roll back to previous commit |
healthcheck.yml |
Scheduled | Periodic service health check |
release.yml |
Tag push v* |
Generate release notes + attach artifacts |
Branch structure
| Branch | Purpose |
|---|---|
main |
Production-ready, auto-deploys to hub |
dev |
Active development, auto-deploys to test (if enabled) |
feature/* |
Short-lived feature branches, PR to dev |
hotfix/* |
Urgent fixes off main, PR to both main and dev |
Commit convention
All commits use Conventional Commits format with a trailing period: : .
| Type | Use for |
|---|---|
feat: |
New functionality |
fix: |
Bug fixes |
chore: |
Dependencies, tooling, refactors |
docs: |
Documentation only |
ci: |
CI/CD workflow changes |
perf: |
Performance improvements |
test: |
Adding or updating tests |
style: |
Formatting only, no logic change |