- Added daemon command with --interval, --pid-file, --since flags - Configurable check interval (s/m/h/d format) - PID file for status checking - Graceful shutdown on SIGTERM/SIGINT - Structured logging to stderr for systemd journal - Updated README with daemon docs and systemd service template - Added daemon tests (parse_interval, PID file, help)
234 lines
7.8 KiB
Markdown
234 lines
7.8 KiB
Markdown
# GitHub Release Monitor
|
|
|
|
A CLI tool that tracks GitHub releases or tags from user-defined repositories and exposes them as a subscribable RSS feed.
|
|
|
|
Some repositories (e.g., Zammad) only use git tags without creating GitHub releases — both modes are supported.
|
|
|
|
## Features
|
|
|
|
- Track **releases** or **tags** per repository
|
|
- SQLite storage with automatic deduplication
|
|
- RSS 2.0 feed with markdown-stripped release notes
|
|
- Built-in HTTP server for local feed access
|
|
- Rate-limit-aware GitHub API client
|
|
- Configurable via environment variables and CLI flags
|
|
- Daemon mode for automatic background checks
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install .
|
|
```
|
|
|
|
Or install in development mode:
|
|
|
|
```bash
|
|
pip install -e .
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Set your GitHub token (optional, increases rate limit from 60/h to 5000/h)
|
|
export GH_TOKEN=your_token
|
|
|
|
# Add repositories to track
|
|
ghrel add golang/go # Track releases (default)
|
|
ghrel add zammad/zammad --tags # Track tags
|
|
|
|
# Fetch latest releases/tags
|
|
ghrel check
|
|
|
|
# List tracked repositories
|
|
ghrel list
|
|
|
|
# Start the RSS feed server
|
|
ghrel serve
|
|
```
|
|
|
|
The RSS feed is available at `http://127.0.0.1:8080/feed.xml`.
|
|
|
|
## CLI Commands
|
|
|
|
```
|
|
ghrel # Main command
|
|
├── --version # Show version
|
|
├── --verbose / -v # Enable verbose/debug output
|
|
├── --quiet / -q # Suppress non-essential output
|
|
├── --db-path <path> # Override database path
|
|
├── add <owner/repo> [--tags] # Add a repository to track
|
|
├── remove <owner/repo> # Remove a repository
|
|
├── update <owner/repo> [--tags] [--release] # Update tracking mode
|
|
├── list # List all tracked repositories
|
|
├── check [--since N] # Fetch latest releases/tags
|
|
├── daemon [--interval 30m] # Run as background daemon
|
|
└── serve [--port 8080] [--host 127.0.0.1] # Start HTTP server
|
|
```
|
|
|
|
### `add <owner/repo> [--tags]`
|
|
|
|
Add a repository to track. Validates the format and pings the GitHub API to verify the repository exists.
|
|
|
|
```bash
|
|
ghrel add golang/go # Track releases
|
|
ghrel add zammad/zammad --tags # Track tags
|
|
```
|
|
|
|
### `remove <owner/repo>`
|
|
|
|
Remove a repository and its associated entries.
|
|
|
|
```bash
|
|
ghrel remove golang/go
|
|
```
|
|
|
|
### `update <owner/repo> [--tags] [--release]`
|
|
|
|
Update the tracking mode for an existing repository.
|
|
|
|
```bash
|
|
ghrel update zammad/zammad --tags
|
|
ghrel update zammad/zammad --release
|
|
```
|
|
|
|
### `list`
|
|
|
|
Display tracked repositories with entry counts and last check time.
|
|
|
|
```
|
|
REPO MODE ENTRIES LAST CHECKED
|
|
golang/go release 12 2025-01-15 10:30
|
|
zammad/zammad tag 8 2025-01-15 10:30
|
|
```
|
|
|
|
### `check [--since N]`
|
|
|
|
Fetch latest releases or tags for all tracked repositories. With `--since`, only fetch entries published in the last N hours (e.g., `--since 24h`).
|
|
|
|
```bash
|
|
ghrel check # Fetch all new entries
|
|
ghrel check --since 24h # Only entries from the last 24 hours
|
|
```
|
|
|
|
### `serve [--port PORT] [--host HOST]`
|
|
|
|
Start the HTTP server.
|
|
|
|
```bash
|
|
ghrel serve # Default: 127.0.0.1:8080
|
|
ghrel serve --port 9090 --host 0.0.0.0 # Custom port and host
|
|
```
|
|
|
|
### `daemon [--interval INTERVAL] [--pid-file PATH] [--since N]`
|
|
|
|
Run as a background daemon that periodically checks all tracked repositories for new releases or tags.
|
|
|
|
```bash
|
|
ghrel daemon # Default: 30m interval
|
|
ghrel daemon --interval 1h # Check every hour
|
|
ghrel daemon --interval 15m # Check every 15 minutes
|
|
ghrel daemon --pid-file /run/ghrel.pid # Custom PID file
|
|
ghrel daemon --since 24h # Only entries from last 24h
|
|
```
|
|
|
|
**Interval format**: `N` followed by `s` (seconds), `m` (minutes), `h` (hours), or `d` (days).
|
|
|
|
The daemon writes a PID file for status checking and sends structured logs to stderr (suitable for systemd journal). It handles `SIGTERM` and `SIGINT` for graceful shutdown.
|
|
|
|
#### Systemd Service
|
|
|
|
Create `/etc/systemd/system/ghrel-daemon.service`:
|
|
|
|
```ini
|
|
[Unit]
|
|
Description=GitHub Release Monitor Daemon
|
|
After=network.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/usr/local/bin/ghrel daemon --interval 30m --pid-file /run/ghrel.pid
|
|
Restart=on-failure
|
|
RestartSec=10
|
|
Environment=GH_TOKEN=your_token_here
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
|
|
Enable and start:
|
|
|
|
```bash
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable --now ghrel-daemon
|
|
sudo systemctl status ghrel-daemon
|
|
```
|
|
|
|
View logs:
|
|
```bash
|
|
journalctl -u ghrel-daemon -f
|
|
```
|
|
```
|
|
|
|
## Configuration
|
|
|
|
| Setting | Default | Override |
|
|
|---------------|----------------------------|-------------------|
|
|
| `db_path` | `~/.config/ghrel/repos.db` | `--db-path` flag |
|
|
| `gh_token` | `GH_TOKEN` env var | — |
|
|
| `server_host` | `127.0.0.1` | `--host` flag |
|
|
| `server_port` | `8080` | `--port` flag |
|
|
|
|
## RSS Feed
|
|
|
|
The feed follows RSS 2.0 specification:
|
|
|
|
- **Title**: `GitHub Release Monitor`
|
|
- **Items**: Sorted by `published_at` (newest first), capped at 50 items
|
|
- **Release entries**: Title from release name, description from markdown-stripped body (truncated at 300 characters)
|
|
- **Tag entries**: Title from tag name, description as `Tag {tag_name}`
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────┐
|
|
│ CLI Interface │
|
|
│ (add, remove, update, list, check, serve) │
|
|
├──────────────────────────────────────────────────┤
|
|
│ Core Logic │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌────────┐ │
|
|
│ │ config.py │ │ db.py │ │github.py│ │
|
|
│ │ (defaults, │ │ (sqlite3) │ │(httpx) │ │
|
|
│ │ env vars) │ │ │ │ │ │
|
|
│ └──────────────┘ └──────┬───────┘ └───┬────┘ │
|
|
│ │ │ │
|
|
│ ┌────────▼──────────────▼────┐ │
|
|
│ │ rss.py │ │
|
|
│ │ (xml.etree + markdown) │ │
|
|
│ └──────────────┬─────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────▼─────────────┐ │
|
|
│ │ server.py │ │
|
|
│ │ (http.server, stdlib) │ │
|
|
│ │ (/feed.xml endpoint) │ │
|
|
│ └─────────────────────────────┘ │
|
|
└──────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Testing
|
|
|
|
```bash
|
|
pytest
|
|
```
|
|
|
|
## Dependencies
|
|
|
|
| Package | Purpose |
|
|
|--------------|------------------------------------------|
|
|
| `httpx` | HTTP client for GitHub API |
|
|
| `markdown` | Convert markdown to HTML |
|
|
| `bleach` | Strip HTML tags for plain text |
|
|
| `pytest` | Testing framework |
|
|
| `respx` | Mocking HTTP requests for tests |
|
|
|
|
No heavy frameworks. `http.server` and `xml.etree.ElementTree` are stdlib.
|