Updater local de repos GitHub baixados em zip.
Escaneia a pasta, detecta o dono de cada repo, checa o remoto e atualiza com backup — tudo numa página, sem build.
| Passo | Como |
|---|---|
| SCAN | Lista pastas extraídas + .zips da pasta base |
| DETECTA | Descobre owner/repo sozinho: convenção owner__repo, URL salva, ou metadados dentro do zip (package.json, pyproject.toml, Cargo.toml, go.mod, README…) |
| SUGERE | Sem dono? Busca candidatos na Search API do GitHub ordenados por ⭐ — um clique mapeia |
| CHECA | Compara o commit da branch mapeada × commit remoto (com cache de 10 min) |
| ATUALIZA | Baixa o archive pinado no commit verificado, troca a pasta (ou só o .zip no modo SÓ-ZIP) com backup .bak |
| REVERTE | Volta para o backup em um clique |
# 1. Clone e entre
git clone https://github.com/yanhenrique-dev/GithubRepo-sync.git
cd GithubRepo-sync
# 2. Ambiente
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt pytest
# 3. Token (opcional, mas recomendado: 60 → 5000 checks/hora)
cp .env.example .env
# edite o .env e ponha um token só-leitura de github.com/settings/tokens
# 4. Rode (terminal)
uvicorn app:app --port 8000Ou com ícone na bandeja (abre o navegador sozinho; fechar o ícone para o servidor):
./tray.py # porta 8000
./tray.py 8123 # outra portaAbra http://127.0.0.1:8000, cole a pasta dos repos — a detecção é automática.
- Filtros — Todos · Mapeados · Sem dono · Desatualizados · Atualizados · Erros + busca por nome
- Auto — com ligado, escanear já emenda no check
- Modo Pastas / Só-ZIP — atualiza a pasta extraída ou troca só o
.zip - Badge da API — na sidebar:
TOKEN OK · 4711/5000,SEM TOKEN · 60/HouTOKEN INVÁLIDO
| Método | Rota | Para quê |
|---|---|---|
| GET | /api/health |
Verifica se servidor local está pronto |
| GET | /api/scan?path= |
Lista itens da pasta com mapeamento |
| GET | /api/check?path= |
Consulta a branch no GitHub e marca behind |
| GET | /api/suggest?q= |
Candidatos owner/repo por nome |
| GET | /api/token |
Status do token + cota (nunca expõe o token) |
| GET | /api/log |
Últimas linhas do log |
| POST | /api/map |
Salva {path, name, url, branch} |
| POST | /api/mode |
Alterna {path, zip_only} |
| POST | /api/backup |
Alterna {path, backup} |
| POST | /api/update |
Atualiza {path, name} |
| POST | /api/rollback |
Reverte {path, name} para o .bak |
├── app.py # FastAPI + rotas
├── core/
│ ├── contract.py # contrato canônico das respostas (Pydantic) + response_model
│ ├── scanner.py # descobre pastas/zips e resolve owner/repo
│ ├── zipmeta.py # lê dono de dentro do zip (sem rede)
│ ├── github.py # API do GitHub: check, suggest, cota
│ ├── updater.py # download, troca, backup, rollback
│ └── state.py # mapping / state / config por pasta (.alldown/)
├── static/ # front vanilla: index.html, tokens.css, components.css,
│ # components-optional.css (fora do crítico), shell.css,
│ # app.js, theme.js, contract/openapi.json
├── tests/js/ # testes do frontend (node --test, sem build)
├── pyproject.toml # lint e pytest
└── requirements.txt
Por pasta escaneada, o mapeamento fica em <pasta>/repos.json e o estado em <pasta>/.alldown/ (state.json, config.json) — o .env com o token nunca sai da sua máquina. state.json guarda SHA da pasta e do ZIP separadamente, evitando status incorreto quando ambos existem.
Ícones MynaUI (MIT © Praveen Juge), embutidos como SVG inline.
Execute estes comandos antes de abrir pull request:
.venv/bin/python -m pytest tests/ -q # 169 testes (backend + contrato)
node --test tests/js/*.test.mjs # 38 testes do frontend
node --check static/app.js
uvx --from ruff==0.16.8 ruff check app.py core tray.py tests/
uvx --from pyright==1.1.414 pyright --pythonpath .venv/bin/python app.py core tray.pycore/contract.py é o artefato canônico do formato das respostas. As rotas
declaram response_model=, então o FastAPI valida a resposta no boundary.
static/contract/openapi.json é o snapshot OpenAPI versionado, conferido por
teste.
Renomear ou remover um campo quebra um teste — de qualquer lado da fronteira. Ver docs/CONTRACT.md.
- Mantenha Uvicorn em
127.0.0.1; não exponha esta API sem autenticação própria.ALLDOWN_ALLOW_REMOTE=1remove bloqueio local, mas exige proxy/autenticação externa confiável. - Use branch explícita no mapeamento quando quiser fixar uma branch; sem branch, o app consulta a branch padrão do repositório. Mapeamentos criados pela interface registram
branch_explicit; arquivos legados combranch: "main"continuam compatíveis com fallback automático. .alldown, arquivos de estado, backups e ZIPs têm limites de tamanho e swap transacional para evitar perda de conteúdo.
MIT — use, quebre, melhore.