diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..18473c9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,22 @@ +# Syntaxe : <@utilisateur ou @org/équipe> + +# Par défaut : tout changement requiert une review de ces personnes +* @benslimane-byte + +# Les workflows CI/CD ne peuvent être modifiés que par le lead DevOps +.github/workflows/ @benslimane-byte + +# Le fichier de dépendances requiert une validation technique +ressources/requirements.txt @benslimane-byte + +# Les fichiers de sécurité requièrent une double validation +.github/dependabot.yml @benslimane-byte +.github/CODEOWNERS @benslimane-byte +# Tout changement requiert une approbation de votre binôme +* @benslimane-byte @bambstk + +# Les workflows ne peuvent être modifiés qu'avec validation des deux +.github/workflows/ @benslimane-byte @bambstk + +# Le code applicatif +ressources/ @benslimane-byte @bambstk diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..991d7c0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,25 @@ +version: 2 + +updates: + # GitHub Actions : surveille les "uses: action/nom@version" dans les workflows + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" # "daily" ou "monthly" aussi possible + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" # les commits Dependabot auront le préfixe "ci:" + + # pip : surveille requirements.txt dans /ressources + - package-ecosystem: "pip" + directory: "/ressources" + schedule: + interval: "weekly" + labels: + - "dependencies" + - "python" + open-pull-requests-limit: 5 + commit-message: + prefix: "chore" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a27357..ecb9a31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,44 @@ -name: CI +name: CI — NexaCloud API on: push: - branches: [ "main" ] + branches: [main] pull_request: - branches: [ "main" ] + branches: [main] jobs: - build: + lint: runs-on: ubuntu-latest steps: - - name: Checkout code + - name: Checkout uses: actions/checkout@v4 - - name: Example step - run: echo "Add your build/test steps here!" + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Installer flake8 + run: pip install flake8 + + - name: Lint avec flake8 + run: flake8 ressources/ --config ressources/.flake8 + + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Installer les dépendances + run: pip install -r ressources/requirements.txt + + - name: Lancer les tests + run: pytest ressources/ -v diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml new file mode 100644 index 0000000..934c867 --- /dev/null +++ b/.github/workflows/cicd.yml @@ -0,0 +1,73 @@ +name: CI/CD — NexaCloud API + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + qualite: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Installer les dépendances + run: pip install -r ressources/requirements.txt + + - name: Lint + run: flake8 ressources/ --config ressources/.flake8 + + - name: Tests avec couverture + run: pytest ressources/ -v --cov=ressources --cov-report=term-missing + + staging: + runs-on: ubuntu-latest + needs: qualite + environment: staging + if: github.ref_name == 'main' + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Installer les dépendances + run: pip install -r ressources/requirements.txt + + - name: Déployer sur Azure App Service (staging) + uses: azure/webapps-deploy@v3 + with: + app-name: "ABstaging" + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_STAGING }} + package: ressources/ + + production: + runs-on: ubuntu-latest + needs: staging + environment: production + if: github.ref_name == 'main' + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Installer les dépendances + run: pip install -r ressources/requirements.txt + + - name: Déployer sur Azure App Service (production) + uses: azure/webapps-deploy@v3 + with: + app-name: "ABproduction" + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }} + package: ressources/ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..1c264f9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,22 @@ +name: Deploy + +on: + workflow_dispatch: + +jobs: + deploy-staging: + runs-on: ubuntu-latest + environment: staging # utilise l'environnement staging + + steps: + - name: Déployer en staging + run: echo "Déploiement en staging..." + + deploy-production: + runs-on: ubuntu-latest + environment: production # TODO: ajouter la dépendance sur deploy-staging + needs: deploy-staging + + steps: + - name: Déployer en production + run: echo "Déploiement en production !" diff --git a/.github/workflows/hello.yml b/.github/workflows/hello.yml new file mode 100644 index 0000000..2bcad31 --- /dev/null +++ b/.github/workflows/hello.yml @@ -0,0 +1,27 @@ +name: Hello NexaCloud + +on: + push: + branches: [main] + workflow_dispatch: + +jobs: + salutation: + runs-on: ubuntu-latest + + steps: + - name: Checkout du code + uses: actions/checkout@v4 + + - name: Informations sur l'environnement + run: | + echo "Repo : ${{ github.repository }}" + echo "Branche : ${{ github.ref_name }}" + echo "Commit : ${{ github.sha }}" + echo "Acteur : ${{ github.actor }}" + + - name: Lister les fichiers du repo + run: ls -la + + - name: Date et heure du runner + run: date diff --git a/.github/workflows/secrets.yml b/.github/workflows/secrets.yml new file mode 100644 index 0000000..5bda96e --- /dev/null +++ b/.github/workflows/secrets.yml @@ -0,0 +1,25 @@ +name: Demo Secrets + +on: + workflow_dispatch: + +jobs: + demo: + runs-on: ubuntu-latest + + env: + API_KEY: ${{ secrets.API_KEY }} # injection du secret comme variable d'environnement + + steps: + - name: Vérifier que le secret est défini + run: | + if [ -z "$API_KEY" ]; then + echo "❌ Le secret API_KEY n'est pas défini" + exit 1 + fi + echo "✅ Le secret API_KEY est défini (${#API_KEY} caractères)" + + - name: Simuler un appel API authentifié + run: | + echo "Appel à l'API avec Authorization: Bearer ***" + # En vrai : curl -H "Authorization: Bearer $API_KEY" https://api.example.com diff --git a/.gitignore b/.gitignore index 78e7733..66ee655 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ terraform.rc # Optional: ignore plan files saved before destroying Terraform configuration # Uncomment the line below if you want to ignore planout files. -# planout \ No newline at end of file +# planout diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7693d59 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,24 @@ +# .pre-commit-config.yaml — version complète +repos: + - repo: https://github.com/pycqa/flake8 + rev: 7.3.0 + hooks: + - id: flake8 + args: [--config, ressources/.flake8] + files: ressources/.*\.py$ + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-merge-conflict + - id: check-added-large-files + args: [--maxkb=500] + + - repo: https://github.com/pycqa/isort + rev: 9.0.0a3 + hooks: + - id: isort # trie automatiquement les imports Python + files: ressources/.*\.py$ diff --git a/README.md b/README.md index 4abe121..c264a77 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # TP GitHub Actions — CI/CD et automatisation -**Durée estimée :** 6h -**Prérequis :** Git, GitHub, bases Bash ou PowerShell (TPs précédents) +**Durée estimée :** 6h +**Prérequis :** Git, GitHub, bases Bash ou PowerShell (TPs précédents) **Environnement :** tout OS avec Git installé et un compte GitHub actif --- @@ -242,7 +242,7 @@ Commitez et pushez. Observez l'exécution dans l'onglet **Actions**. > ✏️ **À vous** > -> Ajoutez un step qui affiche la date et l'heure du runner avec `date`. +> Ajoutez un step qui affiche la date et l'heure du runner avec `date`. > Puis déclenchez le workflow **manuellement** depuis l'interface GitHub (bouton "Run workflow").
diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..1f511cb --- /dev/null +++ b/notes.md @@ -0,0 +1 @@ +# Mon TP GitHub Actions ! diff --git a/ressources/__pycache__/app.cpython-314.pyc b/ressources/__pycache__/app.cpython-314.pyc new file mode 100644 index 0000000..8a104e1 Binary files /dev/null and b/ressources/__pycache__/app.cpython-314.pyc differ diff --git a/ressources/__pycache__/test_app.cpython-314-pytest-8.2.0.pyc b/ressources/__pycache__/test_app.cpython-314-pytest-8.2.0.pyc new file mode 100644 index 0000000..8f93bd2 Binary files /dev/null and b/ressources/__pycache__/test_app.cpython-314-pytest-8.2.0.pyc differ diff --git a/ressources/app.py b/ressources/app.py index d7e75f2..eee358d 100644 --- a/ressources/app.py +++ b/ressources/app.py @@ -38,5 +38,14 @@ def logs_critical(): return jsonify({"critical_count": seuil, "alerte": alerte}) +@app.route("/logs/stats") +def logs_stats(): + total = sum(LOG_SUMMARY.values()) + return jsonify({ + "total": total, + "breakdown": LOG_SUMMARY + }) + + if __name__ == "__main__": app.run(debug=True, port=5001) diff --git a/ressources/test_app.py b/ressources/test_app.py index ce56a43..a886678 100644 --- a/ressources/test_app.py +++ b/ressources/test_app.py @@ -57,3 +57,13 @@ def test_logs_critical_alerte(client): assert "critical_count" in data assert "alerte" in data assert data["alerte"] is True + + +def test_logs_stats(client): + """La route /logs/stats retourne le total et le détail.""" + response = client.get("/logs/stats") + assert response.status_code == 200 + data = response.get_json() + assert "total" in data + assert "breakdown" in data + assert data["total"] == 185 # 142 + 28 + 12 + 3