docs: add README covering install, bot reviews, migration, restore
This commit is contained in:
parent
af50266471
commit
06e11f4220
1 changed files with 255 additions and 0 deletions
255
README.md
Normal file
255
README.md
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
# forgejo-stack
|
||||
|
||||
A self-hosted Forgejo + Claude Code integration in a portable Docker Compose
|
||||
stack. Tar it up, move it to any Linux box with Docker, untar, run
|
||||
`./setup.sh` — done.
|
||||
|
||||
## What's in the box
|
||||
|
||||
- **Forgejo** at `http://localhost:3000`, SSH at `ssh://git@localhost:2222`
|
||||
- **Postgres 16** as Forgejo's database
|
||||
- **forgejo-runner** for Forgejo Actions (GitHub Actions compatible)
|
||||
- **forgejo-mcp** sidecar so Claude Code can drive PR/issue/repo operations
|
||||
natively via MCP
|
||||
- **Claude + Gemini review bots** that auto-comment on PRs in any repo you
|
||||
opt in via `bootstrap-repo.sh`
|
||||
- **GitHub migration** via `scripts/migrate-from-github.sh`
|
||||
|
||||
## Requirements
|
||||
|
||||
- Linux (or WSL2)
|
||||
- Docker 24+ with the compose plugin
|
||||
- `curl`, `jq`, `awk`, `git`, `ssh` (usually preinstalled)
|
||||
- ~2 GB free disk (data grows with your repos)
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
git clone <stack-repo-url> forgejo-stack
|
||||
cd forgejo-stack
|
||||
# Optional: edit .env.example to set your hostname/ports/API keys before
|
||||
# first run. .env is auto-created from .env.example with random secrets
|
||||
# filled in.
|
||||
./setup.sh
|
||||
```
|
||||
|
||||
The script is idempotent — re-running it is safe and a no-op for things
|
||||
that already exist.
|
||||
|
||||
When done:
|
||||
|
||||
- Web UI: `http://localhost:3000`
|
||||
- Admin user: see `FORGEJO_ADMIN_USER` in `.env` (defaults to `forgejo_admin`
|
||||
— Forgejo reserves `admin` as a username)
|
||||
- Admin password: see `FORGEJO_ADMIN_PASSWORD` in `.env`
|
||||
|
||||
Run `./scripts/smoke-test.sh` to verify the install end-to-end.
|
||||
|
||||
## Configuration
|
||||
|
||||
Everything lives in `.env`. Notable knobs:
|
||||
|
||||
| Var | Default | Purpose |
|
||||
|---------------------------|------------------|----------------------------------------------------------|
|
||||
| `FORGEJO_DOMAIN` | `localhost` | Used in every URL Forgejo emits |
|
||||
| `FORGEJO_SSH_DOMAIN` | `localhost` | Used for SSH clone URLs |
|
||||
| `FORGEJO_HTTP_PORT` | `3000` | Host port for the web UI |
|
||||
| `FORGEJO_SSH_PORT` | `2222` | Host port for git-over-SSH |
|
||||
| `FORGEJO_ADMIN_USER` | `forgejo_admin` | Admin username (cannot be `admin` — Forgejo reserves it) |
|
||||
| `ANTHROPIC_API_KEY` | (empty) | Required for Claude review bot. If empty, bot skips. |
|
||||
| `GEMINI_API_KEY` | (empty) | Required for Gemini review bot. |
|
||||
| `CLAUDE_BOT_ENABLED` | `true` | Set `false` to disable Claude reviews globally |
|
||||
| `GEMINI_BOT_ENABLED` | `true` | Set `false` to disable Gemini reviews globally |
|
||||
| `GITHUB_TOKEN` | (empty) | Required for `migrate-from-github.sh`. Scopes: `repo`, `read:org` |
|
||||
| `DOCKER_GID` | `984` | Host docker group GID — runner needs it to talk to the docker socket |
|
||||
|
||||
After editing `.env`, re-run `./setup.sh` to apply (it's idempotent).
|
||||
|
||||
## Bot reviews
|
||||
|
||||
Both review bots run as Forgejo Actions workflows. Forgejo 10 does **not**
|
||||
propagate workflows from a `<owner>/.forgejo` repo to other repos under the
|
||||
same owner (verified empirically), so each repo has to opt in explicitly:
|
||||
|
||||
```bash
|
||||
./scripts/bootstrap-repo.sh <owner>/<repo>
|
||||
# or, with the default admin owner:
|
||||
./scripts/bootstrap-repo.sh <repo>
|
||||
```
|
||||
|
||||
That copies `.forgejo/workflows/{claude,gemini}-review.yml` into the target
|
||||
repo. The org-level repo `<owner>/.forgejo` (created by `setup.sh`) is the
|
||||
canonical source — `bootstrap-repo.sh` reads from it and falls back to the
|
||||
`templates/` directory in this stack if the org repo file is missing.
|
||||
|
||||
After opt-in, both bots auto-review on PR open and on every push. To skip
|
||||
a single PR, add the `skip-bot-review` label.
|
||||
|
||||
To disable a bot for **all** repos: edit `.env`, set
|
||||
`CLAUDE_BOT_ENABLED=false` (or `GEMINI_BOT_ENABLED=false`), re-run
|
||||
`./setup.sh`.
|
||||
|
||||
To customize the prompt for a single repo, commit
|
||||
`.forgejo/prompts/claude-review.md` (or `gemini-review.md`) into the repo —
|
||||
the workflow uses repo-local prompts when present and falls back to the
|
||||
defaults from the `<owner>/.forgejo` repo.
|
||||
|
||||
## Migrating from GitHub
|
||||
|
||||
```bash
|
||||
# Single repo (default forgejo owner = FORGEJO_ADMIN_USER)
|
||||
./scripts/migrate-from-github.sh octocat/Hello-World
|
||||
|
||||
# All public repos owned by an account
|
||||
./scripts/migrate-from-github.sh --all <gh-username>
|
||||
|
||||
# Include private repos (token must have repo scope)
|
||||
./scripts/migrate-from-github.sh --all <gh-username> --include-private
|
||||
|
||||
# Replace an already-migrated target
|
||||
./scripts/migrate-from-github.sh octocat/Hello-World --force
|
||||
```
|
||||
|
||||
Known limitations of GitHub→Forgejo migration:
|
||||
|
||||
- `@username` mentions in issues/PRs become orphaned (Forgejo can't resolve
|
||||
them to local users)
|
||||
- PR review threads can flatten into top-level comments
|
||||
- Reactions on comments may drop
|
||||
- GitHub Actions workflow files migrate as-is. Most work under Forgejo
|
||||
Actions; some `actions/...` references may need adjustment
|
||||
|
||||
After migration, run `./scripts/bootstrap-repo.sh <owner>/<repo>` if you
|
||||
want bot reviews on the migrated repo.
|
||||
|
||||
## Moving the stack to a new machine
|
||||
|
||||
```bash
|
||||
# On the source box
|
||||
docker compose down
|
||||
tar czf forgejo-stack.tgz -C "$(dirname "$PWD")" "$(basename "$PWD")"
|
||||
|
||||
# Transfer however you like
|
||||
scp forgejo-stack.tgz target:~/
|
||||
|
||||
# On the target
|
||||
tar xzf forgejo-stack.tgz
|
||||
cd forgejo-stack
|
||||
./setup.sh --restore
|
||||
```
|
||||
|
||||
`--restore` keeps existing Forgejo data (admin user, tokens, runner
|
||||
registration, repos all survive), and only re-creates the per-host
|
||||
artifacts that don't travel inside the data dirs:
|
||||
|
||||
- `~/space/.mcp.json` — registers the forgejo MCP server with Claude Code
|
||||
- `~/.claude/projects/-home-luffy-space/memory/forgejo-local.md` — reference
|
||||
memory entry pointing Claude Code at the stack
|
||||
|
||||
## Upgrading to LAN or public hostname
|
||||
|
||||
The stack ships localhost-first. To expose on your LAN or the internet:
|
||||
|
||||
1. Edit `.env`:
|
||||
```
|
||||
FORGEJO_DOMAIN=forge.example.com
|
||||
FORGEJO_SSH_DOMAIN=forge.example.com
|
||||
FORGEJO_ROOT_URL=https://forge.example.com/
|
||||
```
|
||||
2. (Public TLS only) Copy the Caddy override and bring the stack up with it:
|
||||
```
|
||||
cp docker-compose.caddy.yml.example docker-compose.caddy.yml
|
||||
docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
|
||||
```
|
||||
Caddy provisions Let's Encrypt automatically. Ports 80 and 443 must be
|
||||
reachable from the public internet.
|
||||
3. Re-run `./setup.sh` so the bootstrap reflects the new URLs in workflows
|
||||
and memory.
|
||||
|
||||
## Security notes
|
||||
|
||||
- The `forgejo-runner` container mounts `/var/run/docker.sock`. That is
|
||||
effectively root on the host. If this matters to you, switch the runner to
|
||||
host-mode execution at the cost of slower job startup.
|
||||
- The runner container joins the host's docker group via `group_add`. The
|
||||
default GID is `984`; override with `DOCKER_GID` in `.env` if your host
|
||||
uses a different group.
|
||||
- Bot tokens (`CLAUDE_BOT_TOKEN`, `GEMINI_BOT_TOKEN`) are stored as
|
||||
Forgejo Actions secrets. They are not visible in finished workflow logs by
|
||||
default, but anyone with admin access to your Forgejo can read them.
|
||||
- API keys (`ANTHROPIC_API_KEY`, `GEMINI_API_KEY`) live both in `.env` and
|
||||
as Forgejo Actions secrets. Keep `.env` out of git (already gitignored).
|
||||
- `bootstrap-forgejo.sh` deletes Forgejo Actions secrets when their value
|
||||
is empty in `.env` (Forgejo rejects empty-string PUTs with 422). So
|
||||
leaving an API key blank disables the corresponding bot — it does not
|
||||
leave a stale secret behind.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Setup fails on `wait_for_url`**: Forgejo is slow to start the first
|
||||
time on a fresh box. Re-run `./setup.sh`; the container will already be
|
||||
up by then.
|
||||
- **`forgejo admin user create` rejects the username**: Forgejo reserves
|
||||
certain usernames (`admin`, `api`, `assets`, …). Pick another value for
|
||||
`FORGEJO_ADMIN_USER` in `.env`. The default is `forgejo_admin`.
|
||||
- **SSH on port 22 is wedged or "address already in use"**: do not enable
|
||||
`START_SSH_SERVER=true` in the Forgejo container — the upstream image
|
||||
already bundles its own SSH stack and the two collide. The compose file
|
||||
ships with `START_SSH_SERVER=false`; leave it that way.
|
||||
- **Runner stuck "waiting for /data/.runner-token"**: bootstrap writes the
|
||||
token then restarts the runner. If the file never appears, check that
|
||||
the admin token in `.env` works
|
||||
(`curl -H "Authorization: token $FORGEJO_ADMIN_TOKEN" http://localhost:3000/api/v1/version`).
|
||||
- **Runner exits with `permission denied … /var/run/docker.sock`**: the
|
||||
in-container UID isn't in the host's docker group. Find the GID with
|
||||
`getent group docker | cut -d: -f3` and set `DOCKER_GID` in `.env`,
|
||||
then `docker compose up -d --force-recreate runner`.
|
||||
- **No runner-list endpoint on Forgejo 10**: Forgejo's API exposes only
|
||||
`/admin/runners/registration-token`, not a list endpoint. The smoke test
|
||||
checks `data/runner/.runner` instead — that file is written by
|
||||
`forgejo-runner` on successful registration.
|
||||
- **`docker exec` into `forgejo-mcp` returns "exec: \"/bin/sh\": not found"**:
|
||||
the `ronmi/forgejo-mcp` image is `FROM scratch` — there is no shell, no
|
||||
`ls`, just the binary. The long-running container exposes an HTTP MCP
|
||||
endpoint (port `8181` by default); Claude Code itself launches a fresh
|
||||
`docker run --rm -i … stdio` container per session via the entry in
|
||||
`~/space/.mcp.json`.
|
||||
- **MCP not visible to Claude Code**: `cat ~/space/.mcp.json` should show
|
||||
`mcpServers.forgejo`. Restart Claude Code so it re-reads the config.
|
||||
- **Bot review didn't fire**: the most common cause is forgetting to opt
|
||||
the repo in. Run `./scripts/bootstrap-repo.sh <owner>/<repo>` once. Then
|
||||
check that the org-level secrets are set
|
||||
(`Site Administration → Actions → Secrets`), the runner is online, and
|
||||
the PR doesn't have the `skip-bot-review` label.
|
||||
- **Bot review still skips after I added an API key**: re-run `./setup.sh`.
|
||||
API keys are pushed into Forgejo Actions secrets only when bootstrap
|
||||
runs. Without re-running, the workflow expands `${{ secrets.X }}` to an
|
||||
empty string and short-circuits.
|
||||
- **`PUT /user/actions/secrets` returns 422 [Data]: Required**: Forgejo 10
|
||||
rejects empty string secrets. The bootstrap detects this and `DELETE`s
|
||||
the secret instead, which lets workflows short-circuit cleanly. If you
|
||||
see this 422 directly, it's because something else is calling the API
|
||||
with an empty value.
|
||||
|
||||
## Repository layout
|
||||
|
||||
```
|
||||
forgejo-stack/
|
||||
├── docker-compose.yml # 4-service stack: db, forgejo, runner, forgejo-mcp
|
||||
├── docker-compose.caddy.yml.example # opt-in TLS reverse proxy override
|
||||
├── .env.example # all stack config
|
||||
├── setup.sh # entry point — idempotent
|
||||
├── scripts/
|
||||
│ ├── lib.sh # shared bash helpers
|
||||
│ ├── bootstrap-forgejo.sh # provisions admin/tokens/bots/runner/secrets
|
||||
│ ├── bootstrap-repo.sh # opts a single repo into bot reviews
|
||||
│ ├── migrate-from-github.sh # GitHub → Forgejo migration
|
||||
│ └── smoke-test.sh # end-to-end verification
|
||||
├── templates/
|
||||
│ ├── workflows/ # claude-review.yml, gemini-review.yml
|
||||
│ └── prompts/ # default review prompts (markdown)
|
||||
└── data/ # all persistent state — gitignored
|
||||
├── db/ # postgres
|
||||
├── forgejo/ # forgejo (repos, users, lfs, …)
|
||||
└── runner/ # forgejo-runner state
|
||||
```
|
||||
Loading…
Add table
Reference in a new issue