mirror of
https://github.com/terraphim/gitea-infrastructure.git
synced 2026-07-16 01:00:33 +02:00
- Remove sync-to-gitea.yml and mirror-check.yml GitHub Actions workflows - Set up Gitea as pull mirror from GitHub (1h interval, via POST /repos/migrate) - Rewrite MIRRORING-GUIDE.md with pull mirror setup and gotchas - Update HANDOVER.md and lessons-learned.md with new approach Gitea now automatically pulls from GitHub. No Actions, no dual-push, no billing dependency. Push to GitHub only; Gitea syncs within 1 hour. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
165 lines
5.6 KiB
Markdown
165 lines
5.6 KiB
Markdown
# Repository Mirroring: GitHub -> Gitea Pull Mirror
|
|
|
|
## Overview
|
|
|
|
GitHub is the primary repository. Gitea automatically pulls from GitHub every hour using its native pull mirror feature. No GitHub Actions, no manual dual-push, no cron jobs.
|
|
|
|
```
|
|
Developer -> git push -> GitHub (primary)
|
|
|
|
|
v (automatic, every 1h)
|
|
Gitea (read-only mirror)
|
|
```
|
|
|
|
## Current Configuration
|
|
|
|
| Setting | Value |
|
|
|---------|-------|
|
|
| Primary | https://github.com/terraphim/gitea-infrastructure (private) |
|
|
| Mirror | https://git.terraphim.cloud/terraphim/gitea-infrastructure |
|
|
| Direction | GitHub -> Gitea (one-way pull) |
|
|
| Interval | 1 hour |
|
|
| Service | `github` (uses GitHub API for private repo access) |
|
|
| Auth | GitHub token stored in Gitea migration config |
|
|
|
|
## Daily Workflow
|
|
|
|
Push to GitHub only. Gitea syncs automatically.
|
|
|
|
```bash
|
|
git push origin main
|
|
```
|
|
|
|
That is all. Gitea pulls within 1 hour.
|
|
|
|
## Manual Sync
|
|
|
|
Trigger an immediate sync without waiting for the interval:
|
|
|
|
```bash
|
|
source ~/op_zesticai_non_prod.sh
|
|
GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
|
|
|
|
curl -s -X POST \
|
|
"https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure/mirror-sync" \
|
|
-H "Authorization: token $GITEA_TOKEN"
|
|
```
|
|
|
|
## Check Mirror Status
|
|
|
|
```bash
|
|
source ~/op_zesticai_non_prod.sh
|
|
GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
|
|
|
|
curl -s "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
|
|
-H "Authorization: token $GITEA_TOKEN" | \
|
|
jq '{mirror, mirror_interval, mirror_updated, empty, size}'
|
|
```
|
|
|
|
## Change Sync Interval
|
|
|
|
```bash
|
|
curl -s -X PATCH \
|
|
"https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"mirror_interval": "30m"}'
|
|
```
|
|
|
|
Minimum interval is 10 minutes (enforced by Gitea server config).
|
|
|
|
## Recreating the Mirror
|
|
|
|
If the mirror breaks (e.g., GitHub token expires, repo gets corrupted):
|
|
|
|
```bash
|
|
source ~/op_zesticai_non_prod.sh
|
|
GITEA_TOKEN=$(op read "op://TerraphimPlatform/git.terraphim.cloud-admin-token/credential")
|
|
GH_TOKEN=$(gh auth token)
|
|
|
|
# Step 1: Delete existing mirror
|
|
curl -s -X DELETE \
|
|
"https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
|
|
-H "Authorization: token $GITEA_TOKEN"
|
|
|
|
# Step 2: Wait for deletion to complete
|
|
sleep 10
|
|
|
|
# Step 3: Verify deleted
|
|
curl -s "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
|
|
-H "Authorization: token $GITEA_TOKEN" -w "\nHTTP %{http_code}\n"
|
|
# Should return HTTP 404
|
|
|
|
# Step 4: Recreate as pull mirror
|
|
curl -s -X POST "https://git.terraphim.cloud/api/v1/repos/migrate" \
|
|
-H "Authorization: token $GITEA_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"clone_addr\": \"https://github.com/terraphim/gitea-infrastructure\",
|
|
\"repo_name\": \"gitea-infrastructure\",
|
|
\"repo_owner\": \"terraphim\",
|
|
\"service\": \"github\",
|
|
\"auth_token\": \"$GH_TOKEN\",
|
|
\"mirror\": true,
|
|
\"mirror_interval\": \"1h\"
|
|
}"
|
|
|
|
# Step 5: Verify (wait a few seconds for async clone)
|
|
sleep 15
|
|
curl -s "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure" \
|
|
-H "Authorization: token $GITEA_TOKEN" | \
|
|
jq '{id, mirror, mirror_interval, mirror_updated, empty, size}'
|
|
# Should show: mirror: true, empty: false
|
|
```
|
|
|
|
## Critical Gotchas
|
|
|
|
### 1. Existing repos cannot be converted to mirrors
|
|
|
|
Gitea only creates mirrors via the `POST /repos/migrate` endpoint. There is no way to convert an existing repo to a mirror. You must delete and recreate.
|
|
|
|
### 2. The `service` field matters for private repos
|
|
|
|
| Service | Behavior |
|
|
|---------|----------|
|
|
| `github` | Uses GitHub API. Requires `auth_token` for private repos. |
|
|
| `git` | Uses `git clone`. Fails with "terminal prompts disabled" for private repos. |
|
|
|
|
Always use `service: "github"` with a valid GitHub token for private repositories.
|
|
|
|
### 3. Failed migrations leave empty repos
|
|
|
|
If the async clone fails (bad token, network error), Gitea still creates the repo entry with `mirror: true, empty: true`. The `mirror-sync` endpoint returns "Repository is not a mirror" on these broken repos. Delete and recreate.
|
|
|
|
### 4. The `github.personal.token` in 1Password is expired
|
|
|
|
As of 2026-02-18, the `op://TerraphimPlatform/github.personal.token/token` returns a token that GitHub rejects with HTTP 401. Use `gh auth token` instead for a working token.
|
|
|
|
### 5. Wait between delete and create
|
|
|
|
Gitea needs time to fully delete a repo. Without a `sleep 10` between delete and create, you get `409 Conflict: The repository with the same name already exists`.
|
|
|
|
## Why Not GitHub Actions?
|
|
|
|
The previous approach used two GitHub Actions workflows:
|
|
- `sync-to-gitea.yml` -- pushed to Gitea on every GitHub push
|
|
- `mirror-check.yml` -- checked sync status every 6 hours
|
|
|
|
Problems:
|
|
1. GitHub Actions billing issues caused silent failures
|
|
2. Required storing a `GITEA_TOKEN` secret in GitHub
|
|
3. Consumed GitHub Actions minutes
|
|
4. Added unnecessary complexity
|
|
|
|
The Gitea pull mirror replaces both workflows with zero configuration on the GitHub side.
|
|
|
|
## API Reference
|
|
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| `POST` | `/api/v1/repos/migrate` | Create repo as pull mirror |
|
|
| `POST` | `/api/v1/repos/{owner}/{repo}/mirror-sync` | Trigger immediate sync |
|
|
| `PATCH` | `/api/v1/repos/{owner}/{repo}` | Change `mirror_interval` |
|
|
| `GET` | `/api/v1/repos/{owner}/{repo}` | Check mirror status |
|
|
| `DELETE` | `/api/v1/repos/{owner}/{repo}` | Delete (before recreating) |
|