- Python 99.2%
- Shell 0.8%
| .agents/skills | ||
| .beans | ||
| .devcontainer | ||
| .forgejo/workflows | ||
| scripts | ||
| src/forgejo_watcher | ||
| tests | ||
| .beans.yml | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| .python-version | ||
| AGENTS.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| renovate.json | ||
| uv.lock | ||
forgejo-watcher
Poll Forgejo for repository changes and trigger actions—no webhooks required.
A lightweight CLI tool that monitors your Forgejo instance, automatically syncs repositories, and triggers systemd services. Ideal when webhooks aren't available or you need a simpler, firewall-friendly alternative.
Quick Start (5 minutes)
Get running in 4 steps:
Step 1: Set Environment Variables
export FW_API_URL="https://your-forgejo.example.com"
export FW_ACTOR="dummy" # Use "dummy" for testing first
If your Forgejo instance requires authentication:
export FW_TOKEN="your-api-token-here"
Step 2: Check Available Actors
$ forgejo-watcher list-actors
Available actors:
dummy - Dummy actor for testing without systemd dependencies
systemd - Start systemd user services (requires: python3-dbus)
Active actor: dummy
Use dummy for testing; switch to systemd for production.
Step 3: Initialize Your Repository Tracking
Fetch all repositories from your Forgejo instance:
$ forgejo-watcher initialize
Loaded 5 repositories from Forgejo:
- myorg/myrepo
- myorg/another-project
- teamA/service-x
- teamA/service-y
- automation/scripts
Step 4: Verify Your Setup
$ forgejo-watcher list-repos
Tracked repositories:
myorg/myrepo
myorg/another-project
teamA/service-x
teamA/service-y
automation/scripts
You're done! forgejo-watcher is now tracking these repositories. See Common Workflows for how to automate synchronization and trigger actions.
Features
- Poll-based monitoring — Check Forgejo for changes on a schedule (no webhooks required)
- Bidirectional synchronization — Automatically add new repositories and remove archived ones
- Pluggable actor system — Extend with custom actions or use built-in integrations
- Systemd service launcher — Start user services when repositories change (D-Bus integration)
- Simple JSON state — Track repositories in a local, human-readable file
- Environment-based configuration — No complex config files; set variables and go
- Lightweight — Python 3.13+, minimal dependencies
- Comprehensive testing — Unit and integration tests included
Requirements
- Python 3.13 or later — Uses modern syntax (match/case expressions, type hints)
- pipx — For installing the tool as a standalone command
- Forgejo instance — With API access (v1 API)
For systemd integration (optional):
python3-dbussystem package — Provides D-Bus bindings for systemd control
For authentication (optional):
- API token (if your instance requires it)
Installation
Standard Installation (Testing/Dummy Actor)
pipx install git+https://forge.sebatec.eu/sebatec-eu/forgejo-watcher.git@main
With Systemd Integration (Recommended for Production)
Systemd integration requires access to D-Bus. Install with system site packages enabled:
pipx install --system-site-packages git+https://forge.sebatec.eu/sebatec-eu/forgejo-watcher.git@main
First install the D-Bus package:
sudo apt install python3-dbus
Verify Installation
forgejo-watcher --help
Configuration
forgejo-watcher uses environment variables for all config. Set them before running commands, or add to .bashrc / .zshrc for persistence.
Required Variables
FW_API_URL (required)
Base URL of your Forgejo instance (no trailing slash).
export FW_API_URL="https://forgejo.example.com"
export FW_API_URL="https://git.company.internal"
Optional Variables
FW_TOKEN (optional)
API token for authentication.
export FW_TOKEN="abc123def456..." # Create from Forgejo Settings → Applications
FW_TOKEN_FILE (optional)
Path to file containing API token. Takes precedence over FW_TOKEN.
export FW_TOKEN_FILE="$HOME/.config/forgejo-watcher/token.txt"
FW_ACTOR (optional)
Actor to use. Defaults to dummy.
export FW_ACTOR="dummy" # Safe testing (logs only)
export FW_ACTOR="systemd" # Production (starts services via D-Bus)
FW_STATE_FILE (optional)
Where to store repositories. Defaults to ~/.local/state/forgejo-watcher/repositories.json.
export FW_STATE_FILE="$HOME/.local/state/forgejo-watcher/repositories.json"
STATE_DIRECTORY (optional)
State directory. Defaults to ~/.local/state/forgejo-watcher.
export STATE_DIRECTORY="$HOME/.local/state/forgejo-watcher"
FW_SERVICE_TEMPLATE (optional)
Template for service names (placeholder {} is replaced with repo). Defaults to forgejo-{}.service.
export FW_SERVICE_TEMPLATE="forgejo-{}.service"
# For org/myrepo, this becomes: forgejo-org-myrepo.service
Example: Production Configuration
export FW_API_URL="https://git.company.internal"
export FW_TOKEN_FILE="$HOME/.config/forgejo-watcher/token.txt"
export FW_ACTOR="systemd"
export FW_SERVICE_TEMPLATE="git-automation-{}.service"
export STATE_DIRECTORY="/var/lib/forgejo-watcher"
Example: Using Token File (Recommended for Security)
export FW_API_URL="https://git.company.internal"
export FW_TOKEN_FILE="$HOME/.config/forgejo-watcher/token.txt"
export FW_ACTOR="systemd"
# Create token file with restricted permissions
echo "glpat_abc123def456xyz..." > "$HOME/.config/forgejo-watcher/token.txt"
chmod 600 "$HOME/.config/forgejo-watcher/token.txt"
Commands Reference
forgejo-watcher provides seven primary commands for managing and monitoring repositories.
initialize [--trigger]
Fetch all repositories from Forgejo and initialize local tracking.
Options:
--trigger— Trigger actor execution for newly discovered repositories
Example:
$ forgejo-watcher initialize
Loaded 3 repositories from Forgejo:
- team/project-a
- team/project-b
- automation/setup-scripts
Repositories saved to: /home/user/.local/state/forgejo-watcher/repositories.json
With --trigger, each new repository will trigger the configured actor (e.g., starting a systemd service).
add <repo_id> [--trigger]
Manually add a repository to tracking without initializing all of them.
Arguments:
repo_id— Repository in the formatorganization/repository
Options:
--trigger— Trigger actor execution for the added repository
Example:
$ forgejo-watcher add team/new-project
Added: team/new-project
Tracked repositories (4 total):
- team/project-a
- team/project-b
- automation/setup-scripts
- team/new-project
remove <repo_id>
Remove a repository from tracking (doesn't delete anything on Forgejo).
Arguments:
repo_id— Repository in the formatorganization/repository
Example:
$ forgejo-watcher remove team/archived-project
Removed: team/archived-project
Tracked repositories (3 total):
- team/project-a
- team/project-b
- automation/setup-scripts
list-repos
Show all currently tracked repositories.
Example:
$ forgejo-watcher list-repos
Tracked repositories (3 total):
- team/project-a
- team/project-b
- automation/setup-scripts
list-actors
Show available actors and check if their prerequisites are met.
Example:
$ forgejo-watcher list-actors
Available actors:
dummy
Dummy actor for testing without systemd dependencies
Status: ✓ Available
systemd
Start systemd user services (requires: python3-dbus)
Status: ✓ Available (python3-dbus is installed)
Active actor: dummy
If D-Bus isn't installed, the systemd actor will show:
systemd
Start systemd user services (requires: python3-dbus)
Status: ✗ Unavailable (python3-dbus not found)
sync [--trigger]
Synchronize your local repository list with Forgejo (bidirectional).
- Adds any new repositories found on Forgejo
- Removes repositories that no longer exist on Forgejo
- Useful for running on a schedule (e.g., cron job)
Options:
--trigger— Execute the actor for newly added repositories
Example:
$ forgejo-watcher sync
Syncing with Forgejo...
New repositories:
+ team/fresh-project
Removed repositories:
- team/archived-project
Repositories saved to: /home/user/.local/state/forgejo-watcher/repositories.json
trigger <repo_id>
Manually execute the configured actor for a specific repository.
Arguments:
repo_id— Repository in the formatorganization/repository
Example (with dummy actor):
$ forgejo-watcher trigger team/project-a
Dummy actor triggered for team/project-a
Example (with systemd actor):
$ forgejo-watcher trigger team/project-a
Started systemd service: forgejo-team-project-a.service
Actors: Triggering Actions
Pluggable handlers that execute actions when repositories change.
What Are Actors?
When you run forgejo-watcher trigger or use --trigger with other commands, the configured actor executes.
Available Actors
dummy Actor (Safe for Testing)
Logs execution without side effects. Safe for testing.
systemd Actor (Production Automation)
Starts user systemd services when repositories change. Integrates with D-Bus to control systemd.
Requires:
python3-dbussystem package- Installation with
--system-site-packages - Pre-configured systemd user services
export FW_ACTOR="systemd"
export FW_SERVICE_TEMPLATE="deploy-{}.service"
forgejo-watcher trigger team/project-a # Starts: deploy-team-project-a.service
Setting Up Systemd Integration
Convert repo names to service names and start them via D-Bus.
Step 1: Create Service File
mkdir -p ~/.config/systemd/user/
Create ~/.config/systemd/user/deploy-team-project-a.service:
[Unit]
Description=Deploy team/project-a
After=network-online.target
[Service]
Type=oneshot
ExecStart=/path/to/your/deploy/script.sh
[Install]
WantedBy=default.target
Step 2: Enable & Reload
systemctl --user daemon-reload
systemctl --user enable deploy-team-project-a.service
Step 3: Configure & Test
export FW_ACTOR="systemd"
export FW_SERVICE_TEMPLATE="deploy-{}.service"
forgejo-watcher trigger team/project-a
Creating Custom Actors
Create a Python module with execute() and check_prerequisites() functions. See Contributing for details.
Common Workflows
Set up tracking for all repositories in your instance:
export FW_API_URL="https://git.company.int"
export FW_TOKEN="your-api-token"
export FW_ACTOR="dummy"
forgejo-watcher list-actors # Verify setup
forgejo-watcher initialize # Fetch all repositories
forgejo-watcher list-repos # Verify state
# Later: switch to production
export FW_ACTOR="systemd"
Keep repositories in sync with a cron job:
0 * * * * export FW_API_URL="https://git.company.int" && \
export FW_TOKEN="token..." && \
/home/user/.local/bin/forgejo-watcher sync >> /var/log/forgejo-watcher.log 2>&1
Runs hourly: adds new repos, removes archived ones.
Automatically start deployment services:
export FW_API_URL="https://git.company.int"
export FW_ACTOR="systemd"
export FW_SERVICE_TEMPLATE="deploy-{}.service"
# Create systemd services for each repo (see Systemd Integration section)
forgejo-watcher sync --trigger
Test your setup:
forgejo-watcher trigger team/project-a
# dummy: logs execution
# systemd: starts the service
Troubleshooting
Can't reach Forgejo?
Verify URL, check connectivity, confirm no firewall blocking.
API token invalid?
Verify token at Forgejo Settings → Applications. Ensure API permissions. Try without token if allowed.
Python3-dbus not found?
sudo apt install python3-dbus
pipx install --system-site-packages git+ssh://git@forge.sebatec.eu/sebatec-eu/forgejo-watcher.git@main
Can't read/write state file?
mkdir -p ~/.local/state/forgejo-watcher
chmod 700 ~/.local/state/forgejo-watcher
Systemd service won't start?
systemctl --user list-unit-files | grep deploy # Service exists?
systemctl --user status deploy-team-project-a.service # Status?
journalctl --user -u deploy-team-project-a.service # Logs?
systemctl --user daemon-reload # Reload systemd
Testing
Run all tests:
uv run pytest tests/ -v
Run integration tests (requires systemd user mode):
uv run pytest tests/test_systemd_integration.py --run-integration -v
Run with coverage:
uv run pytest tests/ --cov=src/forgejo_watcher --cov-report=term-missing
Contributing
Found a bug? Have a feature idea? Open an issue.
When reporting:
- Environment (OS, Python version)
- Exact command + output
- Config (redacted)
- Relevant logs
License
This project is licensed under the GNU General Public License v3.0 (GPLv3). See the LICENSE file for details.