Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,69 @@ on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
test:
name: Tests & Coverage
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests with coverage
run: |
pytest --cov=gitpull --cov-report=xml --cov-report=term-missing
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.python-version }}
path: coverage.xml

pylint:
name: Pylint
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pylint
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')

sonarqube:
name: SonarQube
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install dependencies and run coverage
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pytest --cov=gitpull --cov-report=xml
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@f00de44f574073760c9deaf47f694e10431f3988
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -209,3 +209,4 @@ __marimo__/
demo/demo.json
config.json
/.idea/
nohup.out
5 changes: 5 additions & 0 deletions .sonarlint/connectedMode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sonarCloudOrganization": "lenoirpatrick",
"projectKey": "lenoirpatrick_githubwebhook",
"region": "EU"
}
65 changes: 65 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

A FastAPI-based GitHub webhook server that automatically pulls the latest code from GitHub repositories when a push event is received. Intended for CI/CD deployment on a Raspberry Pi or similar server.

## Commands

### Install dependencies
```shell
pip install -r requirements.txt
```

### Run the server
```shell
python gitpull.py
```

### Lint
```shell
pylint gitpull.py
```

### Run tests
```shell
pytest
```

### Run tests with coverage
```shell
pytest --cov=gitpull --cov-report=term-missing
```

## Architecture

The entire application is in a single file: `gitpull.py`.

- **`/`** — HTML home page with a link to the demo endpoint.
- **`/beats`** — Health check endpoint; returns `{"result": true}`.
- **`/webhook`** (POST) — Receives GitHub push events. Checks the `ref` field; only processes pushes to `refs/heads/main`. Calls `update_webhook()`.
- **`/webhookdemo`** — Triggers a simulated webhook using `demo/demo.json` as the payload. Useful for manual testing.
- **`update_webhook(webhook_github)`** — Core logic: resolves the repo path from `config/config.json`, runs `git reset --hard HEAD~1` then `git pull` in that path.

## Configuration

`config/config.json` maps repository full names (e.g. `"lenoirpatrick/githubwebhook"`) to local paths, and contains the server bind IP:

```json
{
"ip": "127.0.0.1",
"lenoirpatrick/githubwebhook": {
"path": "/home/pi/app/githubwebhook"
}
}
```

The config is loaded at module startup (global scope), so the server must be started from the project root directory.

## CI

`.github/workflows/build.yml` runs two jobs on push to `main`/`develop` and on PRs:
- **SonarQube** — static analysis via SonarCloud (requires `SONAR_TOKEN` secret).
- **pylint** — runs across Python 3.11, 3.12, 3.13 matrix.
99 changes: 94 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ Gestion du webhook Github pour déploiement CI/CD sur vos environnements.
[![GitHub stars](https://img.shields.io/github/stars/lenoirpatrick/githubwebhook)](https://github.com/lenoirpatrick/githubwebhook)
[![GitHub license](https://img.shields.io/github/license/lenoirpatrick/githubwebhook)](https://github.com/lenoirpatrick/githubwebhook)

# Prérequis — Configurer le webhook GitHub

Sur chaque dépôt à déployer, un webhook doit être configuré dans GitHub pour notifier cette application à chaque push.

1. Aller dans **Settings → Webhooks → Add webhook** du dépôt concerné
2. Renseigner les champs suivants :

| Champ | Valeur |
|-------|--------|
| **Payload URL** | `http://<adresse-du-serveur>:5000/webhook` |
| **Content type** | `application/json` |
| **Secret** | La valeur de `webhook_secret` définie dans `config.json` (si configurée) |
| **Which events?** | *Just the push event* |

3. Cocher **Active** et valider.

GitHub enverra alors un événement `POST /webhook` à chaque push. Seuls les pushs sur la branche `main` déclenchent un `git pull`.

# Installation
```shell
git clone githubwebhook.git
Expand All @@ -23,14 +41,85 @@ chmod +x run.sh
```

# Configuration
Dans le répertoire config, créer un fichier config.json

Dans le répertoire `config`, créer un fichier `config.json` :

```json
{
"lenoirpatrick/githubwebhook": {
"path": "/home/pi/app/githubwebhook"
}
"ip": "0.0.0.0",
"webhook_secret": "votre_secret_github",
"lenoirpatrick/githubwebhook": {
"path": "/home/pi/app/githubwebhook"
},
"lenoirpatrick/autreprojet": {
"path": "/home/pi/app/autreprojet"
}
}
```

| Clé | Description |
|-----|-------------|
| `ip` | Adresse d'écoute : `0.0.0.0` pour toutes les interfaces, `127.0.0.1` pour local uniquement |
| `webhook_secret` | Secret partagé avec GitHub pour valider la signature HMAC-SHA256 (optionnel mais recommandé) |
| `"owner/repo"` | Chemin absolu local du dépôt à mettre à jour lors d'un push sur `main` |

Plusieurs dépôts peuvent être configurés simultanément.

# Lancement
Executer le script ```run.sh```

## Manuel

```shell
./run.sh
```

Le script installe les dépendances, puis lance l'application en arrière-plan via `nohup`. Les logs sont disponibles dans `nohup.out`.

## Démarrage automatique avec systemd (recommandé)

Pour que le serveur se lance automatiquement au démarrage de Linux, créer un service systemd.

**1. Créer le fichier de service** (adapter les chemins et l'utilisateur) :

```shell
sudo nano /etc/systemd/system/githubwebhook.service
```

```ini
[Unit]
Description=GitHub Webhook Server
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/app/githubwebhook
ExecStart=/usr/bin/python3 /home/pi/app/githubwebhook/gitpull.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
```

**2. Activer et démarrer le service :**

```shell
sudo systemctl daemon-reload
sudo systemctl enable githubwebhook
sudo systemctl start githubwebhook
```

**3. Vérifier que le service tourne :**

```shell
sudo systemctl status githubwebhook
```

**Commandes utiles :**

```shell
sudo systemctl stop githubwebhook # arrêter
sudo systemctl restart githubwebhook # redémarrer
journalctl -u githubwebhook -f # suivre les logs en temps réel
```
Loading
Loading