feat: add Gitea Actions CI/CD, local checks and deploy guide
This commit is contained in:
@@ -0,0 +1,55 @@
|
|||||||
|
name: Vérification PR
|
||||||
|
run-name: Vérification PR de ${{ gitea.actor }}
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.3'
|
||||||
|
extensions: curl, intl, mbstring, xml
|
||||||
|
|
||||||
|
- name: Lint PHP (tous les fichiers, samples inclus)
|
||||||
|
run: |
|
||||||
|
fail=0
|
||||||
|
while IFS= read -r f; do
|
||||||
|
php -l "$f" > /dev/null || { echo "::error file=$f::Erreur de syntaxe PHP"; fail=1; }
|
||||||
|
done < <(find . -path ./.git -prune -o \( -name '*.php' -o -name '*.php.sample' \) -print)
|
||||||
|
[ "$fail" -eq 0 ] && echo "PHP lint OK" || exit 1
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Lint JS (sw.js et js/*.js)
|
||||||
|
run: |
|
||||||
|
for f in sw.js js/*.js; do
|
||||||
|
node --check "$f" || exit 1
|
||||||
|
done
|
||||||
|
echo "JS lint OK"
|
||||||
|
|
||||||
|
- name: Installer Asciidoctor
|
||||||
|
run: sudo gem install asciidoctor
|
||||||
|
|
||||||
|
- name: Valider README.adoc
|
||||||
|
run: asciidoctor -o /tmp/readme.html README.adoc
|
||||||
|
|
||||||
|
- name: Valider JSON et XML
|
||||||
|
run: |
|
||||||
|
sudo apt-get update && sudo apt-get install -y libxml2-utils
|
||||||
|
python3 -m json.tool site.webmanifest.sample > /dev/null
|
||||||
|
xmllint --noout sitemap.xml.sample browserconfig.xml
|
||||||
|
|
||||||
|
- name: Shellcheck (scripts shell)
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y shellcheck
|
||||||
|
shellcheck docs/generate-readme-pdf.sh scripts/check.sh
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
name: Déploiement PROD
|
||||||
|
run-name: ${{ gitea.actor }} déploie en PROD
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.3'
|
||||||
|
extensions: curl, intl, mbstring, xml
|
||||||
|
|
||||||
|
- name: Lint PHP (tous les fichiers, samples inclus)
|
||||||
|
run: |
|
||||||
|
fail=0
|
||||||
|
while IFS= read -r f; do
|
||||||
|
php -l "$f" > /dev/null || { echo "::error file=$f::Erreur de syntaxe PHP"; fail=1; }
|
||||||
|
done < <(find . -path ./.git -prune -o \( -name '*.php' -o -name '*.php.sample' \) -print)
|
||||||
|
[ "$fail" -eq 0 ] && echo "PHP lint OK" || exit 1
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Lint JS (sw.js et js/*.js)
|
||||||
|
run: |
|
||||||
|
for f in sw.js js/*.js; do
|
||||||
|
node --check "$f" || exit 1
|
||||||
|
done
|
||||||
|
echo "JS lint OK"
|
||||||
|
|
||||||
|
- name: Installer Asciidoctor
|
||||||
|
run: sudo gem install asciidoctor
|
||||||
|
|
||||||
|
- name: Valider README.adoc
|
||||||
|
run: asciidoctor -o /tmp/readme.html README.adoc
|
||||||
|
|
||||||
|
- name: Valider JSON et XML
|
||||||
|
run: |
|
||||||
|
sudo apt-get update && sudo apt-get install -y libxml2-utils
|
||||||
|
python3 -m json.tool site.webmanifest.sample > /dev/null
|
||||||
|
xmllint --noout sitemap.xml.sample browserconfig.xml
|
||||||
|
|
||||||
|
- name: Shellcheck (scripts shell)
|
||||||
|
run: |
|
||||||
|
sudo apt-get install -y shellcheck
|
||||||
|
shellcheck docs/generate-readme-pdf.sh scripts/check.sh
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
needs: check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Déployer sur le serveur
|
||||||
|
uses: appleboy/ssh-action@v1
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.SSH_HOST }}
|
||||||
|
username: ${{ secrets.SSH_USER }}
|
||||||
|
key: ${{ secrets.SSH_KEY }}
|
||||||
|
script: |
|
||||||
|
set -e
|
||||||
|
cd ${{ secrets.PROD_DEPLOY_PATH }}
|
||||||
|
|
||||||
|
# Annuler le bump de version du déploiement précédent pour
|
||||||
|
# garantir le fast-forward, puis récupérer la dernière version.
|
||||||
|
git checkout -- sw.js
|
||||||
|
git pull --ff-only origin main
|
||||||
|
|
||||||
|
# Bumper la version des caches du Service Worker : chaque
|
||||||
|
# déploiement déclenche le modal de mise à jour PWA chez les
|
||||||
|
# visiteurs (voir js/pwa-update.js). Ce bump n'est pas commité.
|
||||||
|
VERSION=$(date +%d%m%Y-%H%M)
|
||||||
|
sed -i "s/annu-kute-ced-static-[0-9]\{8\}-[0-9]\{4\}/annu-kute-ced-static-$VERSION/" sw.js
|
||||||
|
sed -i "s/annu-kute-ced-dynamic-[0-9]\{8\}-[0-9]\{4\}/annu-kute-ced-dynamic-$VERSION/" sw.js
|
||||||
|
echo "Version des caches bumpée : $VERSION"
|
||||||
+278
@@ -0,0 +1,278 @@
|
|||||||
|
= 🚀 DEPLOY — Mise en production et CI/CD
|
||||||
|
:toc: left
|
||||||
|
:toc-title: Sommaire
|
||||||
|
:toclevels: 3
|
||||||
|
|
||||||
|
Ce document décrit la mise en production complète d'*ANNU KUTE CED* sur un serveur fraîchement installé, puis l'activation du déploiement continu via *Gitea Actions*.
|
||||||
|
|
||||||
|
Il est complémentaire au link:README.adoc[README] (installation manuelle, configuration de l'application).
|
||||||
|
|
||||||
|
== 🧭 Vue d'ensemble
|
||||||
|
|
||||||
|
L'architecture retenue (identique à celle de pawol.nu) :
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
┌─────────────┐ push main ┌──────────────────┐ SSH (git pull) ┌─────────────┐
|
||||||
|
│ Dépôt git │ ─────────────▶ │ Gitea Actions │ ─────────────────▶ │ Serveur │
|
||||||
|
│ (LaBola) │ │ check → deploy │ │ production │
|
||||||
|
└─────────────┘ └──────────────────┘ └─────────────┘
|
||||||
|
----
|
||||||
|
|
||||||
|
. *Vérification* (`check-pr.yml` + job `check` de `deploy-prod.yml`) : lint PHP/JS, validation AsciiDoc, JSON, XML, shellcheck. Les mêmes vérifications sont exécutables en local avec `scripts/check.sh`.
|
||||||
|
. *Déploiement* (`deploy-prod.yml`) : le runner se connecte en SSH au serveur, qui tient *un clone du dépôt*, fait `git pull --ff-only`, puis *bumpe la version des caches* du Service Worker (`sw.js`) pour déclencher le modal de mise à jour PWA chez les visiteurs.
|
||||||
|
|
||||||
|
Pourquoi un `git pull` sur le serveur plutôt qu'un rsync : tous les fichiers propres à l'instance (`config.local.php`, `.htaccess`, `sitemap.xml`, `robots.txt`, `site.webmanifest`, `mentions-legales.php`, `dons.php`, `uploads/`, `cache/`) sont ignorés par Git — un pull ne les écrase jamais. Le déploiement est ainsi sans risque pour la configuration de production.
|
||||||
|
|
||||||
|
== 📋 Prérequis
|
||||||
|
|
||||||
|
- Un serveur *Debian 12* ou *Ubuntu 24.04* fraîchement installé, avec accès `root` (ou `sudo`)
|
||||||
|
- Un nom de domaine dont le *DNS pointe vers le serveur* (enregistrement A/AAAA)
|
||||||
|
- Le dépôt Gitea : `git@labola.o-k-i.net:cedric/annu-kute-ced.git`
|
||||||
|
- Un *runner Gitea Actions* opérationnel sur l'instance LaBola (déjà le cas pour pawol.nu)
|
||||||
|
|
||||||
|
NOTE: Sur un hébergement mutualisé (pas d'accès root), adaptez : les fichiers sont déployés dans le docroot fourni par l'hébergeur, et la clé SSH s'ajoute via le panneau de contrôle (o2switch : *Clés SSH* dans cPanel).
|
||||||
|
|
||||||
|
== 1️⃣ Installation des paquets
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
# Apache + PHP (choix retenu pour ce guide ; Nginx possible, voir §5)
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
apt install -y apache2 php libapache2-mod-php \
|
||||||
|
php-curl php-intl php-mbstring php-xml \
|
||||||
|
git curl unzip
|
||||||
|
|
||||||
|
# Vérifier les extensions requises
|
||||||
|
php -m | grep -E 'curl|intl|mbstring|SimpleXML|json'
|
||||||
|
----
|
||||||
|
|
||||||
|
== 2️⃣ Utilisateur de déploiement
|
||||||
|
|
||||||
|
Le runner CI se connectera en SSH avec cet utilisateur. Ne *pas* utiliser root.
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
adduser --disabled-password --gecos "Deploy annu-kute-ced" deploy
|
||||||
|
usermod -aG www-data deploy
|
||||||
|
|
||||||
|
# Répertoire de l'application
|
||||||
|
mkdir -p /var/www/annu-kute-ced
|
||||||
|
chown -R deploy:www-data /var/www/annu-kute-ced
|
||||||
|
----
|
||||||
|
|
||||||
|
== 3️⃣ Clone du dépôt
|
||||||
|
|
||||||
|
Le serveur de production tient un clone du dépôt. Le runner y exécutera `git pull` à chaque déploiement.
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
# Clé SSH du serveur pour lire le dépôt (deploy key Gitea, lecture seule)
|
||||||
|
sudo -u deploy ssh-keygen -t ed25519 -f /home/deploy/.ssh/id_ed25519 -N ""
|
||||||
|
cat /home/deploy/.ssh/id_ed25519.pub
|
||||||
|
----
|
||||||
|
|
||||||
|
. Sur LaBola : *Settings du dépôt → Deploy Keys → Add deploy key* (coller la clé publique, lecture seule suffit).
|
||||||
|
. Puis :
|
||||||
|
+
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
sudo -u deploy git clone git@labola.o-k-i.net:cedric/annu-kute-ced.git /var/www/annu-kute-ced
|
||||||
|
cd /var/www/annu-kute-ced
|
||||||
|
sudo -u deploy git config pull.ff only # sécurité : refuser tout pull non fast-forward
|
||||||
|
----
|
||||||
|
|
||||||
|
== 4️⃣ Fichiers d'instance
|
||||||
|
|
||||||
|
Ces fichiers sont ignorés par Git : ils vivent *uniquement sur le serveur* et ne seront jamais écrasés par les déploiements.
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
cd /var/www/annu-kute-ced
|
||||||
|
sudo -u deploy cp includes/config.local.php.sample includes/config.local.php
|
||||||
|
sudo -u deploy cp conf/.htaccess.sample .htaccess
|
||||||
|
sudo -u deploy cp site.webmanifest.sample site.webmanifest
|
||||||
|
sudo -u deploy cp robots.txt.sample robots.txt
|
||||||
|
sudo -u deploy cp sitemap.xml.sample sitemap.xml
|
||||||
|
sudo -u deploy cp mentions-legales.php.sample mentions-legales.php
|
||||||
|
# Facultatif (page de dons) :
|
||||||
|
# sudo -u deploy cp dons.php.sample dons.php
|
||||||
|
----
|
||||||
|
|
||||||
|
Éditer ensuite les fichiers copiés :
|
||||||
|
|
||||||
|
- `includes/config.local.php` : `APP_HOST_NAME`, sources (PeerTube/Castopod/Mastodon), `CACHE_ENABLED=true` (recommandé pour Castopod), etc. — voir la link:README.adoc#fr-configuration[référence de configuration]
|
||||||
|
- `sitemap.xml`, `robots.txt`, `site.webmanifest` : remplacer `example.com` par le domaine réel
|
||||||
|
- `mentions-legales.php` : remplacer le placeholder `VOTRE-DATE-MAJ`
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
# Le cache de l'API doit être accessible en écriture par PHP
|
||||||
|
mkdir -p /var/www/annu-kute-ced/cache
|
||||||
|
chown -R www-data:www-data /var/www/annu-kute-ced/cache
|
||||||
|
----
|
||||||
|
|
||||||
|
== 5️⃣ VirtualHost
|
||||||
|
|
||||||
|
=== Option A — Apache (recommandée, `.htaccess` fourni)
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
a2enmod rewrite headers
|
||||||
|
cat > /etc/apache2/sites-available/annu-kute-ced.conf <<'EOF'
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName example.com
|
||||||
|
ServerAlias www.example.com
|
||||||
|
DocumentRoot /var/www/annu-kute-ced
|
||||||
|
|
||||||
|
<Directory /var/www/annu-kute-ced>
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
</VirtualHost>
|
||||||
|
EOF
|
||||||
|
a2ensite annu-kute-ced
|
||||||
|
systemctl reload apache2
|
||||||
|
----
|
||||||
|
|
||||||
|
Le `.htaccess` copié à l'étape 4 applique les règles de sécurité, le HTTPS forcé (actif après l'étape 6) et le `no-cache` de `sw.js`.
|
||||||
|
|
||||||
|
=== Option B — Nginx + PHP-FPM
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
apt install -y nginx php-fpm
|
||||||
|
# Adapter conf/nginx.conf.sample : server_name, root, socket php-fpm,
|
||||||
|
# chemins des certificats. ⚠️ Le bloc "location ~* \.(php|inc|...)$ { deny all; }"
|
||||||
|
# de l'exemple correspond à TOUS les .php : le restreindre à ^/includes/.
|
||||||
|
cp conf/nginx.conf.sample /etc/nginx/sites-available/annu-kute-ced
|
||||||
|
ln -s /etc/nginx/sites-available/annu-kute-ced /etc/nginx/sites-enabled/
|
||||||
|
nginx -t && systemctl reload nginx
|
||||||
|
----
|
||||||
|
|
||||||
|
== 6️⃣ HTTPS (obligatoire pour la PWA)
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
apt install -y certbot python3-certbot-apache # ou python3-certbot-nginx
|
||||||
|
certbot --apache -d example.com -d www.example.com
|
||||||
|
# ou : certbot --nginx -d example.com -d www.example.com
|
||||||
|
----
|
||||||
|
|
||||||
|
== 7️⃣ Vérification du site
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
curl -I https://example.com
|
||||||
|
# Attendu : HTTP/2 200, en-têtes de sécurité (CSP, X-Frame-Options…)
|
||||||
|
curl -I https://example.com/sw.js
|
||||||
|
# Attendu : Cache-Control: no-cache
|
||||||
|
----
|
||||||
|
|
||||||
|
Ouvrir le site dans un navigateur : vidéos, podcasts, timeline et le bouton d'installation PWA doivent fonctionner.
|
||||||
|
|
||||||
|
== 8️⃣ Clé SSH du CI
|
||||||
|
|
||||||
|
C'est la clé utilisée par le runner Gitea Actions pour déployer. Elle est *différente* de la deploy key de lecture (étape 3) : celle-ci doit pouvoir écrire dans le clone.
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
# Générer la paire SUR VOTRE POSTE (pas sur le serveur)
|
||||||
|
ssh-keygen -t ed25519 -f annu-kute-ced-deploy -C "ci-gitea-annu-kute-ced"
|
||||||
|
|
||||||
|
# Autoriser la clé publique pour l'utilisateur deploy
|
||||||
|
sudo -u deploy tee -a /home/deploy/.ssh/authorized_keys < annu-kute-ced-deploy.pub
|
||||||
|
----
|
||||||
|
|
||||||
|
La clé privée (`annu-kute-ced-deploy`, sans passphrase) ira dans les secrets Gitea à l'étape suivante. *Conservez-la en lieu sûr et ne la commitez jamais.*
|
||||||
|
|
||||||
|
== 9️⃣ Secrets Gitea
|
||||||
|
|
||||||
|
Dans LaBola : *Settings du dépôt → Actions → Secrets*, créer :
|
||||||
|
|
||||||
|
[cols="1,3",options="header"]
|
||||||
|
|===
|
||||||
|
| Secret | Valeur
|
||||||
|
|
||||||
|
| `SSH_HOST`
|
||||||
|
| Adresse du serveur (IP ou FQDN), port 22 par défaut (sinon `host:port`)
|
||||||
|
|
||||||
|
| `SSH_USER`
|
||||||
|
| `deploy`
|
||||||
|
|
||||||
|
| `SSH_KEY`
|
||||||
|
| Contenu *intégral* de la clé privée générée à l'étape 8
|
||||||
|
|
||||||
|
| `PROD_DEPLOY_PATH`
|
||||||
|
| `/var/www/annu-kute-ced`
|
||||||
|
|===
|
||||||
|
|
||||||
|
WARNING: `SSH_KEY` donne un accès shell au serveur avec les droits de `deploy`. Ne jamais la coller ailleurs que dans les secrets Gitea, et révoquer la clé publique (`authorized_keys`) en cas de doute.
|
||||||
|
|
||||||
|
== 🔟 Test du pipeline
|
||||||
|
|
||||||
|
. Pousser un commit sur `main` (par exemple une correction de coquille dans le README).
|
||||||
|
. Dans LaBola, onglet *Actions* : le workflow *Déploiement PROD* doit exécuter `check` puis `deploy` au vert.
|
||||||
|
. Côté serveur :
|
||||||
|
+
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
cd /var/www/annu-kute-ced
|
||||||
|
git log -1 --oneline # doit correspondre au commit poussé
|
||||||
|
grep STATIC_CACHE_NAME sw.js # le suffixe de version a été bumpé à l'heure du déploiement
|
||||||
|
----
|
||||||
|
. Côté visiteur : au prochain chargement de page, le modal « Nouvelle version disponible » apparaît (Service Worker déjà installé lors d'une visite précédente).
|
||||||
|
|
||||||
|
== 🔄 Fonctionnement courant
|
||||||
|
|
||||||
|
[cols="1,3",options="header"]
|
||||||
|
|===
|
||||||
|
| Événement | Résultat
|
||||||
|
|
||||||
|
| Pull request vers `main`
|
||||||
|
| Workflow *Vérification PR* : lints et validations bloquants en cas d'erreur
|
||||||
|
|
||||||
|
| Push sur `main`
|
||||||
|
| Workflow *Déploiement PROD* : mêmes vérifications, puis SSH → `git pull --ff-only` → bump de la version des caches `sw.js` → modal de mise à jour chez les visiteurs
|
||||||
|
|
||||||
|
| En local, avant de pousser
|
||||||
|
| `scripts/check.sh` exécute les mêmes vérifications que le CI
|
||||||
|
|===
|
||||||
|
|
||||||
|
Le bump de version dans `sw.js` est fait *sur le serveur uniquement* : le dépôt garde sa valeur de référence, le working tree du serveur est nettoyé (`git checkout -- sw.js`) avant chaque pull pour garantir le fast-forward.
|
||||||
|
|
||||||
|
== 🧰 Dépannage
|
||||||
|
|
||||||
|
[cols="1,3",options="header"]
|
||||||
|
|===
|
||||||
|
| Symptôme | Piste
|
||||||
|
|
||||||
|
| `git pull --ff-only` échoue sur le serveur
|
||||||
|
| Une modification locale existe : `git status` dans le docroot, puis `git checkout -- <fichier>` (le workflow le fait déjà pour `sw.js`)
|
||||||
|
|
||||||
|
| L'action ne se déclenche pas
|
||||||
|
| Vérifier que le runner act est en ligne (LaBola → *Site Administration → Actions → Runners*) et que Actions est activé pour le dépôt (*Settings → Units*)
|
||||||
|
|
||||||
|
| `Permission denied (publickey)` dans le job deploy
|
||||||
|
| Clé publique absente de `/home/deploy/.ssh/authorized_keys`, ou mauvais `SSH_USER`/`SSH_HOST`
|
||||||
|
|
||||||
|
| Les visiteurs ne reçoivent pas la mise à jour
|
||||||
|
| Vérifier `curl -I https://example.com/sw.js` → `Cache-Control: no-cache` requis (règles fournies dans `conf/`)
|
||||||
|
|
||||||
|
| Erreurs 500 sur les vidéos/podcasts
|
||||||
|
| `cache/` non accessible en écriture : `chown -R www-data:www-data cache/`
|
||||||
|
|
||||||
|
| `php-intl` manquant
|
||||||
|
| `apt install php-intl && systemctl restart apache2`
|
||||||
|
|===
|
||||||
|
|
||||||
|
== 🔒 Notes de sécurité
|
||||||
|
|
||||||
|
- La clé privée du CI est *dédiée* à ce dépôt : une clé compromise ne donne accès qu'au compte `deploy`, sans sudo.
|
||||||
|
- La deploy key Gitea (étape 3) est en *lecture seule*.
|
||||||
|
- Pour restreindre davantage la clé du CI, on peut limiter les commandes dans `authorized_keys` (`command="..."`, `no-pty`) — facultatif, hors scope de ce guide.
|
||||||
|
- Les fichiers sensibles (`includes/`, `.htaccess`, `config.local.php`) sont bloqués en accès web par les configurations fournies dans `conf/`.
|
||||||
|
|
||||||
|
== 📞 Support
|
||||||
|
|
||||||
|
En cas de blocage : mailto:kontak@o-k-i.net[kontak@o-k-i.net]
|
||||||
+46
@@ -151,6 +151,8 @@ Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <<fr-
|
|||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
|
├── .gitea/
|
||||||
|
│ └── workflows/ # CI/CD Gitea Actions (check-pr, deploy-prod)
|
||||||
├── ajax/
|
├── ajax/
|
||||||
│ └── load-more-videos.php # Endpoint AJAX « Voir plus » (CSRF + Origin)
|
│ └── load-more-videos.php # Endpoint AJAX « Voir plus » (CSRF + Origin)
|
||||||
├── conf/
|
├── conf/
|
||||||
@@ -194,6 +196,8 @@ Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <<fr-
|
|||||||
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
|
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
|
||||||
│ ├── pleroma-adapter.js # Adaptateur Pleroma → API Mastodon
|
│ ├── pleroma-adapter.js # Adaptateur Pleroma → API Mastodon
|
||||||
│ └── pwa-update.js # Enregistrement SW + modal de mise à jour
|
│ └── pwa-update.js # Enregistrement SW + modal de mise à jour
|
||||||
|
├── scripts/
|
||||||
|
│ └── check.sh # Vérifications du CI en local (avant push)
|
||||||
├── uploads/ # Images d'annonces (non versionné, hors .gitkeep)
|
├── uploads/ # Images d'annonces (non versionné, hors .gitkeep)
|
||||||
├── index.php # Page d'accueil (agrégateur)
|
├── index.php # Page d'accueil (agrégateur)
|
||||||
├── video.php # Page de lecture d'une vidéo
|
├── video.php # Page de lecture d'une vidéo
|
||||||
@@ -209,6 +213,7 @@ Toutes ces sources sont modifiables dans `includes/config.local.php` (voir <<fr-
|
|||||||
├── mentions-legales.php.sample # Exemple de mentions légales
|
├── mentions-legales.php.sample # Exemple de mentions légales
|
||||||
├── dons.php.sample # Exemple de page de dons
|
├── dons.php.sample # Exemple de page de dons
|
||||||
├── LICENSE # GNU AGPL v3
|
├── LICENSE # GNU AGPL v3
|
||||||
|
├── DEPLOY.adoc # Guide de déploiement serveur + CI/CD
|
||||||
└── README.adoc
|
└── README.adoc
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -901,6 +906,24 @@ Prérequis : `asciidoctor`, `chromium` (rendu headless) et le paquet `fonts-noto
|
|||||||
|
|
||||||
NOTE: `asciidoctor-pdf` (utilisé par l'extension AsciiDoc de VSCodium) n'est pas utilisable ici : son moteur Prawn ne sait pas embarquer les polices emoji couleur (CBDT/COLR), les émojis disparaissent du PDF. Chromium les gère nativement.
|
NOTE: `asciidoctor-pdf` (utilisé par l'extension AsciiDoc de VSCodium) n'est pas utilisable ici : son moteur Prawn ne sait pas embarquer les polices emoji couleur (CBDT/COLR), les émojis disparaissent du PDF. Chromium les gère nativement.
|
||||||
|
|
||||||
|
==== ✅ Vérifications locales et CI/CD
|
||||||
|
|
||||||
|
Avant de pousser, exécutez les mêmes vérifications que le CI :
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
scripts/check.sh
|
||||||
|
----
|
||||||
|
|
||||||
|
Ce script lance : lint PHP (`php -l` sur tous les fichiers, samples inclus), lint JS (`node --check`), rendu AsciiDoc, validation JSON (`site.webmanifest.sample`) et XML (`sitemap.xml.sample`, `browserconfig.xml`), shellcheck. Un outil manquant est signalé et le check correspondant ignoré ; le CI, lui, exécute tout.
|
||||||
|
|
||||||
|
Pipelines Gitea Actions (`.gitea/workflows/`) :
|
||||||
|
|
||||||
|
- *Vérification PR* (`check-pr.yml`) : sur toute pull request vers `main`
|
||||||
|
- *Déploiement PROD* (`deploy-prod.yml`) : sur push sur `main` — mêmes vérifications, puis déploiement en SSH sur le serveur (`git pull --ff-only` + bump de version du Service Worker, qui déclenche le modal de mise à jour chez les visiteurs)
|
||||||
|
|
||||||
|
La mise en place complète du serveur de production (clone, fichiers d'instance, clés SSH, secrets Gitea) est documentée dans link:DEPLOY.adoc[DEPLOY.adoc].
|
||||||
|
|
||||||
=== 📜 Licence
|
=== 📜 Licence
|
||||||
|
|
||||||
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
|
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
|
||||||
@@ -1055,6 +1078,8 @@ All of these sources can be changed in `includes/config.local.php` (see <<en-con
|
|||||||
|
|
||||||
[source]
|
[source]
|
||||||
----
|
----
|
||||||
|
├── .gitea/
|
||||||
|
│ └── workflows/ # Gitea Actions CI/CD (check-pr, deploy-prod)
|
||||||
├── ajax/
|
├── ajax/
|
||||||
│ └── load-more-videos.php # "Load more" AJAX endpoint (CSRF + Origin)
|
│ └── load-more-videos.php # "Load more" AJAX endpoint (CSRF + Origin)
|
||||||
├── conf/
|
├── conf/
|
||||||
@@ -1098,6 +1123,8 @@ All of these sources can be changed in `includes/config.local.php` (see <<en-con
|
|||||||
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
|
│ ├── mastodon-timeline.umd.js # mastodon-embed-timeline v4.7.0 (vendored)
|
||||||
│ ├── pleroma-adapter.js # Pleroma → Mastodon API adapter
|
│ ├── pleroma-adapter.js # Pleroma → Mastodon API adapter
|
||||||
│ └── pwa-update.js # SW registration + update modal
|
│ └── pwa-update.js # SW registration + update modal
|
||||||
|
├── scripts/
|
||||||
|
│ └── check.sh # CI checks run locally (before pushing)
|
||||||
├── uploads/ # Announcement images (not versioned, except .gitkeep)
|
├── uploads/ # Announcement images (not versioned, except .gitkeep)
|
||||||
├── index.php # Homepage (aggregator)
|
├── index.php # Homepage (aggregator)
|
||||||
├── video.php # Video playback page
|
├── video.php # Video playback page
|
||||||
@@ -1113,6 +1140,7 @@ All of these sources can be changed in `includes/config.local.php` (see <<en-con
|
|||||||
├── mentions-legales.php.sample # Legal notice sample
|
├── mentions-legales.php.sample # Legal notice sample
|
||||||
├── dons.php.sample # Donation page sample
|
├── dons.php.sample # Donation page sample
|
||||||
├── LICENSE # GNU AGPL v3
|
├── LICENSE # GNU AGPL v3
|
||||||
|
├── DEPLOY.adoc # Server deployment + CI/CD guide
|
||||||
└── README.adoc
|
└── README.adoc
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -1805,6 +1833,24 @@ Requirements: `asciidoctor`, `chromium` (headless rendering) and the `fonts-noto
|
|||||||
|
|
||||||
NOTE: `asciidoctor-pdf` (used by VSCodium's AsciiDoc extension) cannot be used here: its Prawn engine cannot embed color-emoji fonts (CBDT/COLR), so emoji disappear from the PDF. Chromium handles them natively.
|
NOTE: `asciidoctor-pdf` (used by VSCodium's AsciiDoc extension) cannot be used here: its Prawn engine cannot embed color-emoji fonts (CBDT/COLR), so emoji disappear from the PDF. Chromium handles them natively.
|
||||||
|
|
||||||
|
==== ✅ Local checks and CI/CD
|
||||||
|
|
||||||
|
Before pushing, run the same checks as the CI:
|
||||||
|
|
||||||
|
[source,bash]
|
||||||
|
----
|
||||||
|
scripts/check.sh
|
||||||
|
----
|
||||||
|
|
||||||
|
This script runs: PHP lint (`php -l` on every file, samples included), JS lint (`node --check`), AsciiDoc rendering, JSON (`site.webmanifest.sample`) and XML (`sitemap.xml.sample`, `browserconfig.xml`) validation, shellcheck. A missing tool is reported and its check skipped; the CI runs everything.
|
||||||
|
|
||||||
|
Gitea Actions pipelines (`.gitea/workflows/`):
|
||||||
|
|
||||||
|
- *PR check* (`check-pr.yml`): on every pull request to `main`
|
||||||
|
- *PROD deployment* (`deploy-prod.yml`): on push to `main` — same checks, then SSH deployment to the server (`git pull --ff-only` + Service Worker version bump, which triggers the update modal for visitors)
|
||||||
|
|
||||||
|
The full production server setup (clone, instance files, SSH keys, Gitea secrets) is documented in link:DEPLOY.adoc[DEPLOY.adoc].
|
||||||
|
|
||||||
=== 📜 License
|
=== 📜 License
|
||||||
|
|
||||||
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
|
Copyright (C) 2025 Cédric Famibelle-Pronzola & *ORGANISATION KA INTERNATIONALE*
|
||||||
|
|||||||
Executable
+106
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Lance en local les mêmes vérifications que le CI (.gitea/workflows/).
|
||||||
|
# À exécuter avant de pousser : scripts/check.sh
|
||||||
|
#
|
||||||
|
# Un outil manquant n'est pas bloquant : le check correspondant est ignoré
|
||||||
|
# avec un avertissement (le CI, lui, exécute tout). Le script retourne un
|
||||||
|
# code non nul si une vérification échoue.
|
||||||
|
|
||||||
|
set -u
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
fail=0
|
||||||
|
warn=0
|
||||||
|
|
||||||
|
step() { printf '\n\033[1m== %s ==\033[0m\n' "$1"; }
|
||||||
|
|
||||||
|
# need <commande> <paquet> : vérifie la présence d'un outil
|
||||||
|
need() {
|
||||||
|
if ! command -v "$1" >/dev/null 2>&1; then
|
||||||
|
echo "⚠️ '$1' non installé — check ignoré (paquet : $2)"
|
||||||
|
warn=1
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
step "PHP lint (*.php, *.php.sample)"
|
||||||
|
if need php php-cli; then
|
||||||
|
php_fail=0
|
||||||
|
while IFS= read -r f; do
|
||||||
|
if ! php -l "$f" > /dev/null; then
|
||||||
|
echo "❌ $f"
|
||||||
|
php_fail=1
|
||||||
|
fi
|
||||||
|
done < <(find . -path ./.git -prune -o \( -name '*.php' -o -name '*.php.sample' \) -print)
|
||||||
|
if [ "$php_fail" -eq 0 ]; then
|
||||||
|
echo "✅ PHP OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "JS lint (sw.js, js/*.js)"
|
||||||
|
if need node nodejs; then
|
||||||
|
js_fail=0
|
||||||
|
for f in sw.js js/*.js; do
|
||||||
|
node --check "$f" || js_fail=1
|
||||||
|
done
|
||||||
|
if [ "$js_fail" -eq 0 ]; then
|
||||||
|
echo "✅ JS OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "AsciiDoc (README.adoc, DEPLOY.adoc)"
|
||||||
|
if need asciidoctor asciidoctor; then
|
||||||
|
adoc_fail=0
|
||||||
|
for f in README.adoc DEPLOY.adoc; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
asciidoctor -o "/tmp/check-$$.html" "$f" || adoc_fail=1
|
||||||
|
done
|
||||||
|
rm -f "/tmp/check-$$.html"
|
||||||
|
if [ "$adoc_fail" -eq 0 ]; then
|
||||||
|
echo "✅ AsciiDoc OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "JSON (site.webmanifest.sample)"
|
||||||
|
if need python3 python3; then
|
||||||
|
if python3 -m json.tool site.webmanifest.sample > /dev/null; then
|
||||||
|
echo "✅ JSON OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "XML (sitemap.xml.sample, browserconfig.xml)"
|
||||||
|
if need xmllint libxml2-utils; then
|
||||||
|
if xmllint --noout sitemap.xml.sample browserconfig.xml; then
|
||||||
|
echo "✅ XML OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
step "Shellcheck (scripts shell)"
|
||||||
|
if need shellcheck shellcheck; then
|
||||||
|
if shellcheck docs/generate-readme-pdf.sh scripts/check.sh; then
|
||||||
|
echo "✅ Shellcheck OK"
|
||||||
|
else
|
||||||
|
fail=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [ "$fail" -ne 0 ]; then
|
||||||
|
echo "❌ Des vérifications ont échoué — corrigez avant de pousser."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$warn" -ne 0 ]; then
|
||||||
|
echo "⚠️ Checks disponibles OK, mais certains outils manquent (le CI exécutera tout)."
|
||||||
|
else
|
||||||
|
echo "✅ Tous les checks passent."
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user