name: MLOps CI Pipeline # 1. TRIGGER: Quando deve partire questa pipeline? # Parte su ogni "push" sul ramo main e su ogni "pull request" on: push: branches: [ "main" ] pull_request: branches: [ "main" ] # Appena attivato il trigger, viene avviato build docker sotto (job2) che richieste l'esecuzione di run_test(job1), se ok parte la creazione dell'immagine docker jobs: # JOB 1: Esecuzione dei Test Automatici run_tests: runs-on: ubuntu-latest # Usa una macchina Linux di GitHub steps: # A. Scarica il codice dalla tua repository - name: Checkout code uses: actions/checkout@v3 # serve proprio a dire al robot di GitHub: "Scarica la versione del codice contenuta in questo specifico commit che ha appena fatto scattare il trigger". # Dobbiamo testare sui nuovi file che stiamo pushando, per questo ci assicuriamo di farlo con i nuovi file # B. Installa Python 3.9 (lo stesso del Dockerfile) - name: Set up Python 3.9 uses: actions/setup-python@v4 with: python-version: "3.9" cache: 'pip' # <--- FONDAMENTALE: Cacha le librerie (così non riscarica le dipendenze ogni volta) # C. Installa le librerie - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Continuous Training (Simulation) run: | # Eseguiamo lo script che controlla i dati e simula il training python src/train.py # D. Lancia Pytest - name: Run Tests run: | python -m pytest # JOB 2: Verifica della Build Docker # Questo job parte SOLO se "run_tests" ha successo (needs: run_tests) build_and_push_docker: needs: run_tests runs-on: ubuntu-latest # Importante: Eseguiamo il push solo se siamo sul ramo 'main' # (non vogliamo pushare immagini di test da altri rami) if: github.ref == 'refs/heads/main' && github.event_name == 'push' steps: - name: Checkout code uses: actions/checkout@v3 # 1. Login su Docker Hub (usa i segreti che hai appena creato) - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} # 2. Build e Push vero e proprio - name: Build and Push run: | # Usa la variabile ${{ secrets.DOCKER_USERNAME }} creata nel repository IMAGE_TAG=${{ secrets.DOCKER_USERNAME }}/reputation-monitor:latest echo "Building image: $IMAGE_TAG" docker build -t $IMAGE_TAG . # Il punto finale indica di usare il Dockerfile nella root della repo, cioè il punto sta a significare "cartella corrente" e va a cercare in automatico il Dockerfile echo "Pushing image to Docker Hub..." docker push $IMAGE_TAG # JOB 3: Push su Hugging Face deploy_to_huggingface: needs: run_tests # Parte solo se i test passano runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 with: fetch-depth: 0 lfs: true - name: Push to Hub env: HF_TOKEN: ${{ secrets.HF_TOKEN }} # Ho creato un token write su HuggingFace che viene utilizzato qui per pushare # Sostituisci col nome del tuo utente HF e del tuo space HF_USERNAME: Faffio # Nome utente SPACE_NAME: Sentiment-Analysis # Nome dello space che ho creato nel mio account run: | # Uso --force per imporre l'aggiornamento di GitHub su Hugging face ignorando la storia di quello che c'è all'interno di Hugging face (se ne frega di quello che c'è dentro, cancella e riaggiorna) git push --force https://$HF_USERNAME:$HF_TOKEN@huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME main # I file vengono salvati nella repository PRIMA che il test parta. È il fatto che tu abbia "pushato" i file che sveglia il robot e gli fa iniziare il lavoro. # Ecco la sequenza temporale esatta: # ⏳ La Timeline Reale # Tu fai git push: I tuoi file vengono caricati su GitHub. In questo istante, il codice nella repository è già aggiornato (anche se fosse rotto). # GitHub vede il cambiamento: "Ehi, è arrivato nuovo codice! Devo lanciare la pipeline". # Parte la CI (Test & Build): GitHub scarica quel codice appena caricato ed esegue i test e la build Docker. # Esito: # 🟢 Se passa: Accanto al tuo commit compare una spunta verde. Tutto bene. # 🔴 Se fallisce: Accanto al tuo commit compare una croce rossa. MA i file restano lì. GitHub non cancella il tuo codice se il test fallisce; ti avvisa solo che è "bacato". # Se il codice rotto viene caricato comunque, a che serve il test? # Professionalmente si crea un ramo diverso della repository, un nuovo branch che non va in produzione, e si pusha li facendo partire CI/CD. POi se tutto ok viene anche aggiornato il main che è sacro # Aggiunta anche una funzione per Pushare il docker container in Hugging Face su uno space creato sul mio account, ho creato il token, lo space e modificato il file readme mettendo codice yaml all'inizio per Hugging face