Come si usa GitHub Actions per creare flussi di lavoro per l'integrazione continua?

Completato

Questo articolo illustra GitHub Actions e i flussi di lavoro per l'integrazione continua.

Scopri come:

  • Creare un flusso di lavoro da un modello
  • Informazioni sui log di GitHub Actions
  • Eseguire test su più destinazioni
  • Separare i processi di compilazione e test
  • Salvare e accedere agli artefatti della compilazione
  • Automatizzare l'assegnazione di etichette a una richiesta pull durante la revisione

Creare un flusso di lavoro da un modello

Per creare un flusso di lavoro, si inizia usando un modello. Un modello include processi comuni e procedure preconfigurate per il tipo di automazione specifico che si sta implementando. Se non si ha familiarità con i flussi di lavoro, i processi e le procedure, vedere il modulo Automatizzare le attività di sviluppo usando GitHub Actions.

Nella pagina principale del repository selezionare la scheda Azioni e quindi selezionare Nuovo flusso di lavoro.

Nella pagina Scegliere un flusso di lavoro è possibile scegliere tra molti modelli diversi. Un esempio è il modello Node.js, che esegue un'installazione pulita delle dipendenze di Node, compila il codice sorgente ed esegue test per versioni diverse di Node. Un altro esempio è il modello Pacchetto Python, che installa le dipendenze di Python ed esegue i test, tra cui i test lint, in versioni diverse di Python.

Nella casella di ricerca, immettere Node.js.

Screenshot showing GitHub Actions tab with the search box highlighted and containing the text 'Node.js'.

Nei risultati della ricerca, nel riquadro Node.js selezionare Configura.

Screenshot showing GitHub Actions tab with the Node.js pane highlighted and the Node.js template selected.

Questo flusso di lavoro predefinito basato sul modello Node.js viene visualizzato nel file node.js.yml appena creato.

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [14.x, 16.x, 18.x]

    steps:
    - uses: actions/checkout@v3
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm run build --if-present
    - run: npm test

Osservare l'attributo on:. Questo flusso di lavoro viene attivato quando viene eseguito un push nel repository e anche quando viene eseguita una richiesta pull nel ramo principale.

In questo flusso di lavoro è presente un job. Di seguito è descritto il risultato.

L'attributo runs-on: specifica che per il sistema operativo il flusso di lavoro viene eseguito su ubuntu-latest. L'attributo node-version: specifica che ci saranno tre compilazioni, per le versioni di Node 14.x, 16.x e 18.x. La parte relativa a matrix verrà illustrata in dettaglio più avanti, al momento di personalizzare il flusso di lavoro.

L'elemento steps nel processo usa l'azione actions/checkout@v3 di GitHub Actions per estrarre il codice dal repository alla macchina virtuale e l'azione actions/setup-node@v3 per configurare la versione corretta di Node.js. Per specificare che verrà eseguito il test di tre versioni di Node.js si usa l'attributo ${{ matrix.node-version }}. Questo attributo fa riferimento alla matrice definita in precedenza. L'attributo cache specifica uno strumento di gestione pacchetti per la memorizzazione nella cache della directory predefinita.

L'ultima parte di questo passaggio esegue i comandi usati dai progetti Node.js. Il comando npm ci installa le dipendenze dal file package-lock.json, npm run build --if-present esegue uno script di compilazione (se esistente) e npm test esegue il framework di testing. Si noti che questo modello include sia la procedura di compilazione sia i passi del test nello stesso processo.

Per altre informazioni su npm, vedere la documentazione di npm:

Log delle azioni per la compilazione

Quando viene eseguito un flusso di lavoro, viene generato un log che include i dettagli di ciò che accade e gli eventuali errori o test non riusciti.

Se si verifica un errore o se un test non riesce, nei log compare una ✖ rossa anziché un segno di spunta ✔ verde. È possibile esaminare i dettagli dell'errore o del test non riuscito per capire cosa è successo.

 GitHub Actions log with details on a failed test.

In questo esercizio si identificano i test non superati esaminando i dettagli nei log. È possibile accedere ai log dalla scheda Azioni.

Personalizzare i modelli di flusso di lavoro

All'inizio di questo modulo è stato descritto uno scenario in cui è necessario configurare l'integrazione continua per il team. Il modello Node.js è un approccio ottimale per iniziare, ma è necessario personalizzarlo per adattarlo meglio ai requisiti del team. Si vuole specificare come destinazione versioni diverse di Node e sistemi operativi diversi. Si vuole anche che la procedura di compilazione e i passi del test siano processi separati.

Verrà ora esaminato come personalizzare un flusso di lavoro.

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node-version: [16.x, 18.x]

In questo esempio è stata configurata una matrice di compilazione per il testing in sistemi operativi e linguaggi diversi. Questa matrice produce quattro compilazioni, una per ogni sistema operativo associato a ogni versione di Node.

Quattro compilazioni con i relativi test producono un volume considerevole di dati di log. Può risultare difficile esaminare tutti questi dati. L'esempio seguente illustra come spostare il passo del test in un processo di test dedicato. Questo processo esegue test su più destinazioni. Separare la procedura di compilazione dai passi del test semplifica la comprensione del log.

test:
  runs-on: ${{ matrix.os }}
  strategy:
    matrix:
      os: [ubuntu-latest, windows-latest]
      node-version: [16.x, 18.x]
  steps:
  - uses: actions/checkout@v3
  - name: Use Node.js ${{ matrix.node-version }}
    uses: actions/setup-node@v3
    with:
      node-version: ${{ matrix.node-version }}
  - name: npm install, and test
    run: |
      npm install
      npm test
    env:
      CI: true

Che cosa sono gli artefatti?

Quando un flusso di lavoro produce qualcosa di diverso da una voce di log, il prodotto è denominato artefatto. Ad esempio, la compilazione di Node.js produce un contenitore Docker che può essere distribuito. Questo artefatto, il contenitore, può essere caricato nello spazio di archiviazione usando l'azione actions/upload-artifact e successivamente scaricato dallo spazio di archiviazione usando l'azione actions/download-artifact.

L'archiviazione di un artefatto permette di conservarlo tra un processo e l'altro. Ogni processo usa una nuova istanza di una macchina virtuale, pertanto non è possibile riutilizzare l'artefatto salvandolo nella macchina virtuale. Se è necessario usare l'artefatto in un processo diverso, è possibile caricarlo in una risorsa di archiviazione in un processo e quindi scaricarlo per l'altro processo.

Archiviazione di artefatti

Gli artefatti vengono archiviati nello spazio di archiviazione in GitHub. Lo spazio è gratuito per i repository pubblici e una certa quantità di spazio è gratuita per i repository privati, a seconda dell'account. GitHub archivia l'artefatto per 90 giorni.

Nel frammento di codice del flusso di lavoro riportato di seguito, si noti che nell'azione actions/upload-artifact@main è presente un attributo path:. Il valore di questo attributo è il percorso in cui archiviare l'artefatto. Qui viene specificato public/ per caricare tutti gli elementi in una directory. Se si volesse caricare un solo file, si potrebbe usare ad esempio public/mytext.txt.

  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: npm install and build webpack
        run: |
          npm install
          npm run build
      - uses: actions/upload-artifact@main
        with:
          name: webpack artifacts
          path: public/

Per scaricare l'artefatto per il testing, è necessario che la compilazione sia stata completata correttamente e che l'artefatto sia stato caricato. Nel codice seguente si specifica che il processo di testing dipende dal processo di compilazione.

test:
    needs: build
    runs-on: ubuntu-latest

Il frammento di codice del flusso di lavoro riportato di seguito visualizza il download dell'artefatto. Ora il processo di testing può usare l'artefatto per il testing.

steps:
    - uses: actions/checkout@v3
    - uses: actions/download-artifact@main
      with:
        name: webpack artifacts
        path: public

Per altre informazioni sull'uso degli artefatti nei flussi di lavoro, vedere Archiviazione dei dati del flusso di lavoro come artefatti nella documentazione di GitHub.

Automatizzare le revisioni in GitHub usando i flussi di lavoro

Finora è stato descritto l'avvio del flusso di lavoro con eventi di GitHub come push o pull-request. È anche possibile eseguire un flusso di lavoro in base a una pianificazione o a un evento esterno a GitHub.

A volte si vuole eseguire il flusso di lavoro solo dopo che una persona ha eseguito un'azione. Ad esempio, è possibile che si voglia eseguire un flusso di lavoro solo dopo che un revisore ha approvato la richiesta pull. Per questo scenario è possibile attivare pull-request-review.

Un'altra azione possibile è l'aggiunta di un'etichetta alla richiesta pull. In questo caso si usa l'azione pullreminders/label-when-approved-action.

    steps:
     - name: Label when approved
       uses: pullreminders/label-when-approved-action@main
       env:
         APPROVALS: "1"
         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         ADD_LABEL: "approved"

Si noti il blocco denominato env:. In questo blocco è possibile impostare le variabili di ambiente per l'azione. Ad esempio è possibile impostare il numero di responsabili approvazione necessari. In questo caso il numero è uno. La variabile di autenticazione secrets.GITHUB_TOKEN è obbligatoria, perché l'azione deve apportare modifiche al repository aggiungendo un'etichetta. Infine si specifica il nome dell'etichetta da aggiungere.

L'aggiunta di un'etichetta può essere un evento che avvia un altro flusso di lavoro, ad esempio un merge. Questo evento verrà trattato nel modulo seguente relativo al recapito continuo con GitHub Actions.