# Searchgit Recherche de dépôts GitHub selon des critères, avec une interface web claire pour parcourir les résultats (thème clair/sombre, responsive, interface en anglais ou en français). L'interface reprend le style de [Logstream](https://gitea.vlab.bzh/cedric/logstream). ## Architecture ![Schéma d'architecture logique de Searchgit](docs/architecture.png) Le navigateur charge l'interface embarquée dans le binaire Go, puis appelle l'API `/api/*` du serveur. Le serveur interroge l'API GitHub Search à travers un cache mémoire de 5 minutes ; le planificateur relance les recherches programmées et enregistre leurs instantanés en JSON dans le volume `searchgit-data`. Le schéma se modifie dans [`docs/architecture.excalidraw`](docs/architecture.excalidraw) (excalidraw.com, menu Ouvrir). ## Démarrage rapide ```bash cp .env.example .env # facultatif : renseigner GITHUB_TOKEN docker compose up -d --build ``` Ouvrir ensuite . Sans Docker : `go run .` (Go 1.24 ou plus récent, données dans `./data`), puis ouvrir . ## Déploiement avec Docker Compose Le fichier `docker-compose.yml` construit l'image à partir du `Dockerfile` et lance un seul conteneur `searchgit` : - le port publié est `HTTP_PORT` (8080 par défaut), redirigé vers le port 8080 du conteneur ; - la configuration est lue dans `.env` (copie de `.env.example`) ; - les recherches programmées et leur historique sont stockés dans le volume nommé `searchgit-data`, monté sur `/data` : ils survivent aux redémarrages et aux mises à jour ; - le conteneur redémarre automatiquement (`restart: unless-stopped`). Exemple de `.env` pour une instance exposée sur le port 8686 avec authentification : ```bash HTTP_PORT=8686 GITHUB_TOKEN=github_pat_... AUTH_USER=admin AUTH_PASS=un-mot-de-passe TZ=Europe/Paris ``` Mettre à jour une instance : ```bash git pull docker compose up -d --build ``` Suivre les journaux : `docker compose logs -f searchgit`. L'état du service est exposé sur `/healthz` (sans authentification), utilisable pour une sonde de supervision. ## Critères | Filtre | Qualificateur GitHub | |---|---| | Champ de recherche | texte libre, plus n'importe quel qualificateur GitHub (`user:`, `org:`, `NOT`, `"phrase exacte"`, `size:`…) | | Partout / Nom / Description / README | `in:name`, `in:description`, `in:readme` | | Langage | `language:Go` (cliquer sur un langage dans la liste pour filtrer dessus) | | Étoiles | `stars:>=100` | | Activité | `pushed:>=AAAA-MM-JJ` (de 1 semaine à 2 ans) | | Date de création | `created:>=AAAA-MM-JJ` | | Licence | `license:mit`… | | Topic | `topic:cli` (cliquer sur un topic dans la liste pour filtrer dessus) | | Good first issues | `good-first-issues:>0` | | Forks / Archivés | les forks et les dépôts archivés sont masqués sauf s'ils sont activés | | Tri | pertinence, plus d'étoiles, plus de forks, mis à jour récemment, issues « help wanted » | Les filtres sont conservés dans l'URL de la page : une recherche peut donc être ajoutée aux favoris ou partagée. Le pied de page affiche la requête exacte envoyée à GitHub (un clic ouvre la même recherche sur github.com). **CSV** télécharge les résultats chargés (séparateur point-virgule quand l'interface est en français, pour Excel). GitHub ne renvoie au maximum que les 1 000 premiers résultats d'une recherche. ## Veille (recherches programmées) **Programmer** enregistre les filtres en cours comme une recherche que le serveur exécute seul : chaque semaine (jour et heure), chaque jour, ou toutes les N heures, dans le fuseau horaire du serveur (`TZ`). Chaque passage conserve un instantané des 30, 50 ou 100 premiers résultats. L'onglet **Veille** liste les recherches programmées avec leur dernier passage. Une page de revue par recherche affiche, pour n'importe quel passage de son historique : - **Nouveautés** : les dépôts jamais renvoyés par un passage précédent de cette recherche ; - **Progressions** : les dépôts qui ont gagné le plus d'étoiles depuis le passage précédent ; - **Tous** : l'instantané complet, avec le gain d'étoiles de chaque dépôt. Une recherche est exécutée une première fois dès sa création : ce premier passage sert de référence pour les suivants. Un passage manqué pendant l'arrêt du serveur est rattrapé au démarrage. Pour une revue hebdomadaire des « pépites », un bon point de départ : un topic ou un langage, *Créé < 1 mois* (ou *Créé < 1 semaine*), trié par *Plus d'étoiles*. ## Configuration | Variable | Défaut | Rôle | |---|---|---| | `HTTP_ADDR` | `:8080` | adresse d'écoute | | `HTTP_PORT` | `8080` | port publié par Docker Compose | | `GITHUB_TOKEN` | vide | jeton GitHub ; fait passer le quota de recherche de 10 à 30 requêtes par minute | | `CACHE_TTL` | `5m` | durée pendant laquelle une recherche identique est servie depuis la mémoire | | `AUTH_USER` / `AUTH_PASS` | vide | authentification HTTP basique (sauf `/healthz`) ; vide = désactivée | | `GITHUB_API` | `https://api.github.com` | URL de base de l'API (GitHub Enterprise) | | `DATA_DIR` | `data` (`/data` sous Docker) | recherches programmées et leurs instantanés (fichiers JSON) | | `TZ` | `Europe/Paris` dans compose | fuseau horaire des programmations | | `HISTORY_KEEP` | `100` | passages conservés par recherche programmée (0 = tous) | Un jeton *fine-grained* sans aucune permission suffit pour les dépôts publics. ## API - `GET /api/search?q=&in=&language=&stars=&maxstars=&minforks=&topic=&license=&pushed=&created=&goodfirst=1&forks=1&archived=1&sort=&order=&page=&per_page=` (`pushed` / `created` : `1w`, `1m`, `3m`, `6m`, `1y`, `2y`, `5y`) - `GET /api/status` : jeton configuré, dernier quota de recherche connu, fuseau horaire du serveur - `GET|POST /api/saved`, `GET|PUT|DELETE /api/saved/{id}` : recherches programmées (`{"name", "params", "maxResults", "enabled", "schedule": {"every": "week|day|hours", "weekday", "hour", "minute", "hours"}}`, `params` étant la chaîne de requête de `/api/search`) - `POST /api/saved/{id}/run` : exécuter maintenant - `GET /api/saved/{id}/runs`, `GET /api/saved/{id}/runs/{run|latest}` : historique et instantanés - `GET /healthz` ## Développement ```bash go test ./... go run . ``` L'interface web est en HTML, CSS et JavaScript simples dans `web/`, embarqués dans le binaire (aucune étape de build).