docs: expand README with setup, configuration and operations

This commit is contained in:
Release Monitor Maintainer
2026-10-11 21:39:06 +07:00
committed by latypov
parent 4e7b8e3e48
commit 8522a2d0a8
+93 -32
View File
@@ -1,22 +1,26 @@
# GitHub Release Monitor
Bash monitor for GitHub releases, with Telegram notifications and SOCKS5 proxy support.
Lightweight Bash monitor that checks GitHub Releases and sends notifications to Telegram through a SOCKS5 proxy. Designed for unattended daily execution with cron. No Python or Docker required.
The default repository list tracks **Lychee**, **Firefly III**, and **Memos**.
## Requirements
- Bash 4+
- curl with SOCKS5 support
- jq
- flock (util-linux)
- mktemp (coreutils)
- Bash 4+ (Linux)
- `curl` with SOCKS5 support
- `jq`
- `flock` (util-linux)
- `mktemp` (coreutils)
- `hostname`, `date`, `awk`, `sed`, `sort`, `tail`
Debian:
On Debian 12/13:
```bash
sudo apt-get install curl jq ca-certificates util-linux
sudo apt-get update
sudo apt-get install -y bash curl jq ca-certificates util-linux coreutils
```
## Setup
## Installation
```bash
cp .env.example .env
@@ -24,53 +28,110 @@ chmod 600 .env
chmod +x monitor.sh
```
Set `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` in `.env`. `GITHUB_TOKEN` is optional for public repositories. `SOCKS5_PROXY` can be set to `socks5h://127.0.0.1:1080`; `socks5h` resolves DNS through the proxy. The `.env` file is sourced as Bash: use only trusted local configuration.
Edit `.env` and supply `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID`. Create a bot with BotFather and send it a message first; the chat ID can then be obtained through Telegram Bot API `getUpdates`. A bot must have access to the destination chat.
Edit `repos.json` to select GitHub repositories. Initial test set: Lychee, Firefly III and Memos.
The script **sources `.env` as Bash code**. Only use a trusted, locally maintained file. Do not commit it.
## Configuration
All settings from `.env.example`:
| Variable | Default | Purpose |
| --- | --- | --- |
| `TELEGRAM_BOT_TOKEN` | empty | Telegram bot token; required for sending |
| `TELEGRAM_CHAT_ID` | empty | Target user/group/channel ID |
| `GITHUB_TOKEN` | empty | Optional GitHub API token; recommended to avoid low anonymous rate limits |
| `SOCKS5_PROXY` | `socks5h://127.0.0.1:1080` | Proxy for both GitHub and Telegram; use `socks5h` for proxy-side DNS |
| `REQUEST_TIMEOUT` | `30` | Maximum time in seconds per HTTP request |
| `GITHUB_PER_PAGE` | `100` | Releases per API page, range 1–100 |
| `GITHUB_MAX_PAGES` | `3` | Maximum pages fetched per repository |
| `REPOS_FILE` | `repos.json` | Repository configuration path |
| `STATE_FILE` | `state.json` | Persisted release IDs |
| `INCLUDE_PRERELEASES` | `false` | Include GitHub prereleases |
| `TELEGRAM_INCLUDE_CHANGELOG` | `true` | Include shortened release notes |
| `TELEGRAM_CHANGELOG_MAX_LENGTH` | `1800` | Maximum release-note characters in each message |
| `STATE_MAX_IDS` | `500` | Maximum stored release IDs per repository |
`REPOS_FILE` and `STATE_FILE` are resolved relative to the script directory unless absolute paths are specified. The default `.env` is loaded from that directory; set `ENV_FILE` to select another configuration file.
For authenticated GitHub requests, use a token with access to the repositories you want to monitor. For public repositories, authentication is optional. GitHub's unauthenticated REST API rate limit is normally 60 requests/hour per originating IP; authenticated requests generally have a larger allowance.
## Repositories
`repos.json` contains GitHub `owner/repo` names:
```json
{
"repositories": [
"LycheeOrg/Lychee",
"firefly-iii/firefly-iii",
"usememos/memos"
]
}
```
Legacy URLs such as `https://github.com/usememos/memos` or `https://www.github.com/usememos/memos.git` are accepted, but `owner/repo` is preferred. The script monitors **GitHub Releases**, not Git tags that have no release object.
## Commands
| Command | Behavior |
| --- | --- |
| `./monitor.sh --test-telegram` | Send one test message, without GitHub requests or reading/writing `repos.json`/`state.json` |
| `./monitor.sh --dry-run --verbose` | Fetch releases, show pending messages and diagnostics, without Telegram delivery or state changes |
| `./monitor.sh --init` | Replace baseline for all configured repositories; do not notify |
| `./monitor.sh` | Normal monitoring: notify for new releases and save successful deliveries |
| `./monitor.sh --include-prereleases` | Include prereleases for this run |
| `./monitor.sh --help` | Show command-line help |
Recommended first run:
```bash
./monitor.sh --test-telegram
./monitor.sh --dry-run --verbose
./monitor.sh --init
./monitor.sh
./monitor.sh --include-prereleases
```
`--test-telegram` sends one Telegram test message without querying GitHub or accessing `state.json`/`repos.json`.
**First-run behavior:** if a repository has no entry in `state.json`, its current releases are recorded as a baseline without notifications. `--init` **replaces** existing baselines, so avoid using it as a routine daily command. A dry run with no baseline prints the currently fetched tags; it does not send them.
`--init` records current releases without notifications; it **replaces** existing baselines. Use only for first initialization or an intentional reset. Normal first run also initializes missing repositories silently.
`--test-telegram` uses the configured proxy and sends a sample changelog if changelogs are enabled. It does not verify GitHub connectivity. `--dry-run` does not send any Telegram message.
`--dry-run` queries GitHub and displays pending notifications without sending or changing state. On a repository without baseline it prints its current release tags.
`--include-prereleases` overrides `INCLUDE_PRERELEASES=false`. To track prereleases continuously, set `INCLUDE_PRERELEASES=true` in `.env`.
State is written atomically after each successful Telegram notification. If Telegram accepted a message but its response was lost, a duplicate may be sent next time. The state contains release IDs and grows over time. A bounded GitHub pagination window (`GITHUB_PER_PAGE * GITHUB_MAX_PAGES`) may miss releases if more are published between checks. For small projects and daily checks this is generally sufficient.
To track prereleases every day, set `INCLUDE_PRERELEASES=true` in `.env` instead of enabling them for occasional runs.
## Daily cron
At 09:00 server-local time:
Run once daily at 09:00 in the server's local timezone:
```cron
0 9 * * * cd /opt/github-release-monitor && ./monitor.sh >> monitor.log 2>&1
```
Run the monitor under a dedicated user where possible. Keep `.env` private and do not commit it. Use `./monitor.sh --test-telegram` to verify Telegram and proxy connectivity.
Use `crontab -e` for the account running the monitor. Change `/opt/github-release-monitor` to your actual installation directory. Keep `monitor.log` under log rotation if it grows; cron output redirection does not rotate logs.
### Large release histories
For troubleshooting:
GitHub response pages are processed through temporary files, rather than passed
through command-line arguments. The state file is read directly by `jq`.
This prevents `Argument list too long` for repositories with large release notes.
```bash
bash -n monitor.sh
./monitor.sh --dry-run --verbose
```
Run `bash -n monitor.sh` and `./monitor.sh --dry-run --verbose` to verify.
## State, ordering, and reliability
### Release notes and retention
- `state.json` records notified release IDs separately for each repository; it is created automatically.
- After successful Telegram delivery, the corresponding release ID is written atomically to state.
- Release notifications are processed oldest-first within the fetched API window.
- `flock -n` prevents overlapping runs; a second invocation exits immediately while another holds the lock.
- If any page of a repository's GitHub response fails, that repository is not processed from a partial response. Other repositories continue; the run exits nonzero if any repository failed.
- GitHub HTTP failures log status and available `X-RateLimit-Remaining`, `X-RateLimit-Reset`, and `Retry-After` headers. The script does not sleep until rate-limit reset.
- The Telegram message contains repository, version, name, publication date, release URL, and optionally a truncated changelog. The message is limited to 4096 Unicode characters.
- GitHub API response pages are processed using temporary files rather than passing large JSON values through process arguments, avoiding `Argument list too long` on long release histories.
`repos.json` uses `owner/repo` names (legacy full GitHub URLs remain accepted).
`TELEGRAM_INCLUDE_CHANGELOG=true` includes a shortened release body in Telegram messages.
`TELEGRAM_CHANGELOG_MAX_LENGTH=1800` limits the changelog; Telegram messages are capped at 4096 characters.
`STATE_MAX_IDS=500` bounds stored release IDs per repository. Keep this larger than the number of releases that may appear in the fetched pages; old releases returning after pruning may otherwise be notified again.
**Retention caveat:** `STATE_MAX_IDS` keeps a bounded set of IDs. Pruned IDs may be treated as new if their releases reappear within the fetched API pages. The fetched window is limited to `GITHUB_PER_PAGE * GITHUB_MAX_PAGES` releases per repository; releases outside it can be missed. Set retention and pagination limits with these trade-offs in mind. The script does not track edited releases or tag-only versions.
GitHub HTTP 403/429 responses log rate-limit headers and fail without changing the repository state. Mid-pagination errors also fail the repository without partially processing it. Tags without GitHub releases are not tracked.
**Delivery caveat:** Telegram does not provide idempotency for `sendMessage`. If it accepted a message but the HTTP response was lost, the next run may resend it. Telegram POST requests are not automatically retried by this script.
## Security and files
Keep `.env` private (`chmod 600 .env`). Do not commit `.env`, `state.json`, lock files, or logs; these are excluded by `.gitignore`. The monitor is intended to run as an unprivileged account.
For a clean installation, copy the tracked project files and configure `.env` locally. Back up `state.json` if migrating an existing installation to avoid reinitializing baselines.