Recherche de site Web

Intégration et déploiement continus pour Python avec les actions GitHub


La création d'un logiciel est une réussite à célébrer. Mais le logiciel n'est jamais statique. Les bogues doivent être corrigés, les fonctionnalités doivent être ajoutées et la sécurité exige des mises à jour régulières. Dans le paysage d'aujourd'hui, avec des méthodologies agiles dominantes, les systèmes DevOps robustes sont cruciaux pour gérer une base de code en évolution. C’est là que les actions GitHub brillent, permettant aux développeurs de Python d’automatiser les workflows et de garantir que leurs projets s’adaptent parfaitement à changer.

GitHub Actions pour Python permet aux développeurs d'automatiser efficacement les flux de travail. Cela permet aux équipes de maintenir la qualité des logiciels tout en s’adaptant aux changements constants.

Les systèmes d'intégration continue et de déploiement continu (CI/CD) aident à produire des logiciels bien testés et de haute qualité et à rationaliser le déploiement. GitHub Actions rend le CI/CD accessible à tous, permettant l'automatisation et la personnalisation des workflows directement dans votre référentiel. Ce service gratuit permet aux développeurs d'exécuter efficacement leurs processus de développement logiciel, améliorant ainsi la productivité et la fiabilité du code.

Dans ce didacticiel, vous apprendrez à :

  • Utilisez les actions GitHub et les workflows
  • Automatiser libinting, test et déploiement d'un projet Python
  • Identifiants sécurisés utilisés pour l'automatisation
  • Automatiser mises à jour de sécurité et de dépendance

Ce didacticiel utilisera une base de code existante, Real Python Reader, comme point de départ pour lequel vous créerez un pipeline CI/CD. Vous pouvez créer le code Real Python Reader sur GitHub pour suivre. Assurez-vous de désélectionner l'option Copier la branche master uniquement lors du forking. Alternativement, si vous préférez, vous pouvez créer votre propre Real Python Reader à l’aide d’un didacticiel précédent.

Afin de tirer le meilleur parti de ce tutoriel, vous devriez être à l'aise avec pip , construire des packages Python, Git et familiariser avec la syntaxe YAML.

Avant de fouiller dans les actions GitHub, il peut être utile de prendre du recul et de découvrir les avantages du CI/CD. Cela vous aidera à comprendre les types de problèmes que les actions GitHub peuvent résoudre.

Bénéficier des avantages du CI/CD

L'Intégration continue (CI) et le Déploiement continu (CD), communément appelés CI/CD, sont des pratiques essentielles dans le développement de logiciels modernes. Ces pratiques automatisent l'intégration des modifications de code, l'exécution de tests et le déploiement d'applications. Cela aide les équipes et les contributeurs open source à apporter des modifications de code plus fréquemment, de manière fiable et structurée.

De plus, lors de la publication de packages Python open source, CI/CD garantira que toutes les demandes d'extraction (PR) et contributions à votre package répondront aux besoins du projet tout en standardisant la qualité du code.

Des déploiements plus fréquents avec des modifications de code plus petites réduisent le risque de modifications brutales involontaires qui peuvent survenir avec des versions plus volumineuses et plus complexes. Par exemple, même si les développeurs peuvent formater tout le code en utilisant les mêmes outils et règles de peluchage, la politique peut automatiquement bloquer la fusion des PR si les tests du code échouent.

Dans la section suivante, vous découvrirez comment les workflows GitHub peuvent vous aider à implémenter CI/CD sur un référentiel hébergé sur GitHub.

Explorer les flux de travail GitHub

Les workflows GitHub sont une fonctionnalité puissante de GitHub Actions. Ils vous permettent de définir des workflows d'automatisation personnalisés pour vos référentiels. Que vous souhaitiez créer, tester ou déployer votre code, les workflows GitHub fournissent une solution flexible et personnalisable que tout projet sur GitHub peut utiliser gratuitement, que le référentiel soit public ou privé.

Même s'il existe de nombreux fournisseurs CI/CD, GitHub Actions est devenue la défaut parmi les projets open-source sur GitHub en raison de son écosystème, de sa flexibilité et de son coût faible ou peu élevé.

Anatomie d'un fichier de workflow

Les fichiers de flux de travail sont des fichiers YAML écrits de manière déclarative avec une structure prédéfinie qui doit être respectée pour qu'un workflow puisse fonctionner avec succès. Vos fichiers YAML Workflow sont stockés et définis dans un dossier .github/workflows/ dans le répertoire racine de votre projet.

Votre dossier de workflow peut avoir plusieurs fichiers de workflow, chacun effectuera une certaine tâche. Vous pouvez nommer ces fichiers de workflow tout ce que vous souhaitez. Cependant, par souci de simplicité et de lisibilité, il est courant de les nommer après les tâches qu'ils accomplissent, telles que test.yml .

Chaque fichier contient quelques éléments obligatoires, mais de nombreux autres éléments facultatifs. La documentation GitHub Actions est complète et bien rédigée, alors assurez-vous de la consulter après avoir fini de lire ce didacticiel.

Il y a trois pièces principales qui composent la majeure partie d'un fichier de workflow: déclenche , emplois et étapes . Vous les couvrirez dans les sections suivantes.

Déclencheurs du flux de travail

Un déclencheur est un événement qui provoque l'exécution d'un flux de travail. Il existe de nombreux types de déclencheurs. Les plus courants sont ceux qui se produisent sur A:

  • Demande de tirage
  • a poussé Commit à la branche par défaut
  • Tagged commit
  • Déclenchement Manuel
  • Demande par un autre flux de travail
  • Nouveau numéro en cours d'ouverture

Vous pouvez également limiter davantage les déclencheurs en le limitant à une branche ou un ensemble de fichiers spécifiques. Voici un exemple simple de déclencheur qui exécute un workflow sur tout pousse vers la branche principale:

on:
  push:
    branches:
      - main

Pour des informations détaillées sur les déclencheurs non couverts dans ce didacticiel, vous pouvez consulter la documentation officielle.

Maintenant que vous savez comment les événements déclenchent des workflows, il est temps d'explorer le prochain composant d'un fichier de workflow: Jobs.

Tâches de flux de travail

Chaque workflow comporte une seule section jobs, qui est le conteneur pour la viande et les pommes de terre du workflow. Un flux de travail peut inclure une ou plusieurs tâches qu'il exécutera, et chaque tâche peut contenir une ou plusieurs étapes.

Voici un exemple de ce à quoi ressemblerait cette section sans aucune étape:

# ...

jobs:
  my_first_job:
    name: My first job
  my_second_job:
    name: My second job

Lorsque vous créez un travail, la première chose à faire est de définir le coureur que vous souhaitez utiliser pour exécuter votre travail. Un Runner est une machine virtuelle (VM) hébergée par GitHub qui exécute vos travaux pour vous. GitHub provisionnera et dérogera la machine virtuelle afin que vous n'ayez pas à vous soucier de maintenir une infrastructure pour votre CI/CD.

Il existe plusieurs systèmes d'exploitation pris en charge disponibles. Vous pouvez trouver la liste complète des coureurs hébergés par Github dans la documentation.

Définir un coureur ne nécessite qu'une seule ligne de YAML :

# ...

jobs:
  my_first_job:
    name: My first job
    runs-on: ubuntu-latest
    # ...
  my_second_job:
    name: My second job
    runs-on: windows-latest
    # ...

Dans l'exemple ci-dessus, my_first_job s'exécutera dans une machine virtuelle Ubuntu, et my_second_job s'exécutera dans une machine virtuelle Windows. Les deux utilisent le suffixe -LaSest dans ce cas, mais vous pouvez également spécifier la version exacte du système d'exploitation - par exemple, ubuntu-20.24 , tant qu'il s'agit d'un support pris en charge version.

Étapes du flux de travail

Les étapes sont la partie principale d'un emploi. Comme vous l'avez probablement deviné, les étapes déclarent les actions qui doivent être effectuées lors de l'exécution du flux de travail. Cela peut inclure des tâches telles que l'installation de Python, l'exécution de tests, le libellé de votre code ou l'utilisation d'une autre action GitHub.

Tout comme votre code Python, les tâches courantes et répétables peuvent être abstraites dans des flux de travail distincts et réutilisées. Cela signifie que vous pouvez et devez utiliser les actions GitHub d'autres personnes dans vos propres flux de travail, de la même manière que vous le feriez lors de l'importation d'une bibliothèque Python, pour vous faire gagner du temps lors de la réimplémentation de cette fonctionnalité.

Dans la section suivante, vous verrez comment utiliser d’autres actions GitHub et comment les trouver.

En utilisant des actions github pour python

Même si les flux de travail font partie des actions GitHub, les flux de travail peuvent également contenir des actions GitHub. En d'autres termes, vous pouvez utiliser les actions des autres ou des organisations dans votre flux de travail. En fait, c'est une pratique courante et fortement encouragée à utiliser les actions GitHub existantes dans vos fichiers de flux de travail. Cette pratique vous fait gagner du temps et des efforts en tirant parti des fonctionnalités prédéfinies.

Si vous avez une tâche spécifique à accomplir, une action GitHub est probablement disponible pour la réaliser. Vous pouvez trouver des actions GitHub pertinentes sur le marché GitHub, que vous découvrirez ensuite.

Explorer le marché GitHub

Le GitHub Marketplace est un référentiel en ligne de toutes les actions que les gens peuvent utiliser dans leurs propres flux de travail. Github, des fournisseurs tiers et des individus construisent et maintiennent ces actions GitHub. Tout le monde peut utiliser le modèle d'action GitHub pour créer sa propre action et l'héberger sur le marché.

Cela a conduit à une vaste gamme d'actions GitHub disponibles pour presque tous les types d'automatisation de tâches imaginables. Toutes les actions du GitHub Marketplace sont open source et gratuites.

Dans la section suivante, vous examinerez deux actions GitHub que vous utiliserez pour chaque projet Python.

Inclure des actions dans les workflows

Chaque flux de travail basé sur Python que vous créez doit non seulement extraire votre référentiel actuel dans l'environnement de flux de travail, mais également installer et configurer Python. Heureusement, GitHub propose des actions GitHub officielles pour vous aider dans les deux tâches :

# ...

jobs:
  my_first_job:
    name: My first job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - run: python -m pip install -r requirements.txt

Dans l'exemple ci-dessus, vous pouvez voir que la première étape de étapes consiste à utiliser l'action officielle cacher . Cette action vérifie le code de votre référentiel dans l'espace de travail GitHub actuel, permettant à votre flux de travail d'y accéder. Le @ 4 suivant Checkout est un spécificateur de version, indiquant quelle version de l'action à utiliser. À l'heure actuelle, la dernière version est V4.2.2, vous pouvez donc vous y référer à l'aide de cette syntaxe pour spécifier la dernière version majeure.

La deuxième étape de cet exemple configure Python dans l'environnement. Encore une fois, cet exemple utilise l'action GitHub officielle pour ce faire en raison de son support et de son développement continus. La plupart des actions, voire la totalité, comportent des configurations supplémentaires que vous pouvez ajouter à l'étape.

La documentation de l'action Installer Python contient la liste complète des configurations. Pour l'instant, le minimum dont vous avez besoin pour installer Python dans votre environnement de workflow est de déclarer la version de Python que vous souhaitez installer.

Dans la dernière étape de l'exemple, vous utilisez la commande run. Cette commande vous permet d'exécuter n'importe quelle commande bash ou powershell, selon le runner que vous utilisez pour l'étape. Dans ce cas, vous installez les dépendances du projet à partir du fichier d'exigences.

J'espère que vous pouvez voir à quel point les actions GitHub peuvent être puissantes. Avec très peu de code et d'efforts, vous avez un moyen reproductible de configurer un environnement prêt à construire, à tester et à déployer votre projet Python.

Vous avez maintenant une compréhension de base de la structure d'un fichier de workflow et comment vous pouvez créer votre premier flux de travail pour un projet. Dans la section suivante, vous ferez exactement cela avec un exemple réel.

Création de votre premier flux de travail

Il est temps de parcourir les étapes d'ajout de CI/CD à un projet réel existant, le Real Python Reader. Avant d'ajouter des flux de travail pour tester et déployer ce package, vous devez d'abord commencer par le peluchage.

Un linter est un outil qui analyse votre code et recherche des erreurs, des problèmes stylistiques et des constructions suspectes. La liaison vous permet de résoudre les problèmes et d'améliorer la qualité de votre code avant de la partager avec d'autres. En démarrant votre CI/CD avec la liaison, vous vous assurerez que votre code est propre et lisible avant de déployer le package sur PYPI.

Pour ce workflow, vous utiliserez Ruff pour pelucher le code Python. Mais si vous ne l'avez pas déjà fait, créez d'abord le référentiel, y compris toutes les branches, puis clonez-le. Assurez-vous de remplacer votre nom d'utilisateur par votre nom d'utilisateur GitHub :

$ git clone git@github.com:your-username/reader.git
$ cd reader/
$ git checkout github-actions-tutorial
$ mkdir -p .github/workflows/

Après avoir cloné votre référentiel à fourche et modifié votre répertoire de travail actuel, vous devrez passer à la branche préexistante nommée github-action-tutorial . Si une telle branche n'est pas disponible, vous avez probablement oublié de décocher l'option Copiez l'option maître seulement lors de la fourniture. Dans un tel cas, vous devez supprimer votre fourchette, revenir au référentiel d'origine, le fourrer à nouveau et vous assurer que vous incluez toutes les branches cette fois.

Une fois que vous avez réussi à basculer vers la bonne branche, créez un dossier pour stocker vos flux de travail. Ce dossier doit s'appeler workflows/ et être un sous-répertoire du dossier .github/.

Vous êtes maintenant prêt à créer votre premier flux de travail dans lequel vous définirez vos déclencheurs, configurerez l’environnement et installerez Ruff. Pour commencer, vous pouvez définir vos déclencheurs dans le fichier lint.yml :

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

Même si cela n'est pas nécessaire, il est considéré comme la meilleure pratique de donner à chacun de vos workflows un nom clair et lisible par l'homme. Ce nom apparaîtra dans la colonne de gauche de l'onglet Actions de votre référentiel GitHub. Il vous aide à identifier les flux de travail et à filtrer disponibles grâce à vos fonctions de workflow précédentes:

Après avoir défini le nom, vous pouvez vous concentrer sur les déclencheurs de ce flux de travail. Dans le code ci-dessus, trois déclencheurs différents sont définis qui peuvent lancer le flux de travail :

  1. Ouverture d'une demande de traction
  2. Pousser les commits locaux
  3. Envoi manuel du workflow

Les deux premiers déclencheront le workflow sur tout événement de demande push ou pull sur la branche master. Cela signifie que toute modification du code déclenchera l'exécution de ce flux de travail, que vous le poussiez directement vers master ou que vous utilisiez une pull request pour fusionner le code dans la branche master de votre dépôt.

Il n'est pas évident ce que fait le déclencheur final. Selon la documentation, il est couramment utilisé pour relancer un flux de travail qui a échoué pour des raisons sans rapport avec les modifications de code, telles qu'une clé API expirée. Cependant, le déclencheur workflow_dispatch fonctionne uniquement lorsque le fichier de workflow est sur la branche par défaut.

Une fois les déclencheurs définis, il est temps de passer à l'étape suivante de la création du fichier de workflow, qui consiste à définir les tâches et à configurer l'environnement :

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  lint: # The name of the job
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"

La plupart de ce code devrait vous sembler familier par rapport aux exemples précédents, mais il existe quelques petites différences. Tout d'abord, vous avez nommé le travail lint pour décrire ce qu'il fait. Ceci est juste un nom, vous pouvez donc choisir le nom de votre choix tant qu'il respecte la syntaxe YAML. Vous avez également défini le programme d'exécution que vous utiliserez pour ce flux de travail comme étant ubuntu-latest.

Ensuite, vous remarquerez que l'action setup-python est désormais configurée pour mettre en cache les dépendances pip de tous les packages installés. Cela permet d'accélérer votre flux de travail lors des exécutions futures si les versions d'un package sont les mêmes. Au lieu de les extraire de PyPI, il utilisera les versions mises en cache.

Maintenant que votre workflow a un déclencheur et un coureur défini, et avec votre code de code et Python installé, il est temps d'installer Ruff et de l'exécuter pour mettre le code. Vous pouvez le faire en ajoutant deux étapes supplémentaires à votre travail peluche :

name: Lint Python Code

on:
  pull_request:
    branches:
      - master
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install ruff

      - name: Run Ruff
        run: ruff check --output-format=github

Dans les deux dernières étapes du travail lint , vous utilisez la commande Exécuter que vous avez vu plus tôt. Dans le cadre de la syntaxe YAML, vous remarquerez un symbole de tuyau ( | ) sur la deuxième ligne. Cela désigne une chaîne multi-lignes. La commande Exécuter interprétera les lignes suivantes comme des commandes distinctes et les exécutera en séquence.

Après avoir installé Ruff, le flux de travail se termine enfin par l'exécution de Ruff pour rechercher les erreurs de peluchage. Avec cette commande, vous pouvez spécifier que vous souhaitez que la sortie soit optimisée pour une exécution dans un workflow github avec la balise --output-format.

Félicitations! Vous avez terminé votre premier flux de travail. Une fois ce workflow validé dans votre référentiel et poussé, GitHub exécutera automatiquement ce workflow de peluchage lorsque la condition de déclenchement est remplie. Vous pouvez également déclencher ce workflow manuellement à tout moment sur le site Web GitHub. Pour ce faire, accédez à l'onglet Actions de votre référentiel, sélectionnez le workflow souhaité dans la partie gauche, puis cliquez sur Exécuter le workflow :

Maintenant que vous avez un flux de travail à votre actif et que vous comprenez comment fonctionnent les flux de travail, il est temps d'en créer un qui exécute la suite de tests sur Real Python Reader.

Création d'un flux de travail de test automatisé

Maintenant que vous avez découvert votre premier workflow GitHub, il est temps d'examiner ce qui sera sans doute le plus important de tous les workflows de ce package : les tests automatisés.

Le Real Python Reader utilise pytest comme framework de test. Et compte tenu de ce que vous avez déjà appris sur les actions GitHub, vous pouvez même voir comment vous pouvez modifier le flux de travail de liaison pour le transformer en flux de travail de test. Après tout, vous allez suivre les mêmes étapes pour vous préparer à exécuter pytest . Il est important de noter que lorsque vous testez un progiciel, vous devez le tester sur toutes les versions prises en charge de Python.

Mais d'abord, comme pour tous les flux de travail GitHub, vous devez déclarer les déclencheurs du flux de travail de test:

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

Une grande partie de ce qui précède est identique au workflow de peluchage précédent, mais avec une différence : il existe désormais un nouveau déclencheur, workflow_call. Tout comme workflow_dispatch, workflow_call est un déclencheur prédéfini qui permet à d'autres workflows de déclencher ce workflow.

Cela signifie que si vous avez un flux de travail à l'avenir qui nécessite également que les tests passent, au lieu de répéter le code, vous pouvez demander au nouveau flux de travail d'utiliser ce flux de travail de test. Le workflow déclenchera ensuite ce flux de travail de test comme l'une de ses étapes et s'assurera qu'il passe avant de passer aux autres étapes du travail. Donc plus de répétition, et vous pouvez garder vos workflows plus courts et précis.

Bien que vous n'utilisiez pas cette méthode de réutilisation du flux de travail dans votre flux de travail test.yml , vous y parviendrez de la même manière que vous appelez d'autres actions GitHub dans votre fichier de workflow, en utilisant le Use mot-clé:

# Github-username/repo/path/to/workflow@version
- uses: realpython/reader/.github/workflows/test.yml@master

Ici, vous pouvez voir que vous pouvez réutiliser un workflow en passant une chaîne de type chemin à use . Il devrait commencer par le nom d'utilisateur GitHub et le nom du référentiel, suivi du chemin vers le fichier de workflow que vous souhaitez utiliser. @master dit au nouveau workflow que vous souhaitez utiliser la version du flux de travail de test de la branche maître . Et maintenant, vous pouvez voir à quel point les actions GitHub peuvent être puissantes. La réutilisation des flux de travail est un énorme avantage des actions GitHub.

Maintenant que vous avez défini les déclencheurs du workflow de test, il est temps de répondre à la question : comment tester sur plusieurs versions de Python ? Dans la section suivante, vous verrez comment définir vos étapes une fois et les exécuter plusieurs fois, chaque exécution étant sur une version différente de Python.

Tests sur plusieurs versions de Python

Dans le flux de travail de liaison, vous avez utilisé l'action configuration-python dans votre étapes pour configurer Python 3.13 dans l'instance Ubuntu, qui ressemblait à ceci:

# ...

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
          cache: "pip"
      # ...
# ...

Malheureusement, vous ne pouvez pas simplement ajouter une liste de versions Python à Python-Version et être fait. Ce dont vous avez besoin est une matrice pour tester plusieurs versions de Python.

Pour citer la documentation officielle:

Une stratégie matricielle vous permet d'utiliser des variables dans une seule définition de travail pour créer automatiquement plusieurs exécutions de travail basées sur les combinaisons des variables. Par exemple, vous pouvez utiliser une stratégie matricielle pour tester votre code dans plusieurs versions d'une langue ou sur plusieurs systèmes d'exploitation. (Source)

En bref, quelles que soient les variables que vous définissez dans votre matrice exécutera les mêmes étapes dans le travail, mais en utilisant ces variables. Ici, vous souhaitez exécuter différentes versions de Python, mais vous pouvez également l'utiliser pour exécuter ou créer votre code sur différents systèmes d'exploitation.

Déclarer une stratégie est relativement simple. Avant de définir vos étapes mais dans le cadre de votre travail, vous pouvez définir la stratégie dont vous avez besoin :

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

Comme vous pouvez le voir, vous déclarez une variable python-version, qui est un tableau de numéros de version. Super, c'est la première partie terminée ! La deuxième partie consiste à indiquer à l'action setup-python que vous souhaitez utiliser ces versions en utilisant une syntaxe de variable spéciale :

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "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 }}
          cache: "pip"

L'étape de configuration Python du workflow a maintenant deux changements. Le premier est le nom ajouté à l'étape. Comme vous l'avez appris plus tôt, cela n'est pas nécessaire, mais cela vous aidera à identifier la version Python a échoué en faisant référence à la version Python au nom de l'étape. Ceci est utile, étant donné que cette étape fonctionnera pour cinq versions différentes de Python.

Le deuxième changement est qu'au lieu de coder dur, le numéro de version dans le avec: Python-Version partie de configuration-python , vous pouvez maintenant vous référer à python- Version définie dans la matrice.

GitHub a quelques contextes spéciaux auxquels vous pouvez accéder dans le cadre de vos workflows. La matrice en fait partie. En définissant la matrice comme faisant partie de la stratégie, python-version est devenue une propriété du contexte matriciel. Cela signifie que vous pouvez accéder à n'importe quelle variable définie comme faisant partie de la matrice avec la syntaxe DOT (. ), par exemple, matrix.python-version .

Bien que ce ne soit pas quelque chose qui doit être fait pour Real Python Reader, vous pouvez faire la même chose avec différentes versions du système d'exploitation. Par exemple:

strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]

Vous pouvez ensuite utiliser la même notation de points pour accéder à la variable OS que vous avez défini dans la matrice avec matrix.os .

Maintenant que vous savez comment utiliser une matrice pour exécuter vos étapes de manière déclarative en utilisant une version différente de Python, il est temps de terminer le flux de travail de test dans son intégralité.

Finalisation du flux de travail de test

Il ne reste que quelques étapes supplémentaires à effectuer pour terminer le flux de travail. Maintenant que Python est installé, le workflow devra installer les dépendances du développeur, puis enfin exécuter pytest.

Le package Real Python Reader utilise un fichier de configuration pyproject.toml pour déclarer ses dépendances. Il comporte également des dépendances de développeur facultatives, qui incluent pytest. Vous pouvez les installer de la même manière que vous avez installé Ruff précédemment, en utilisant la commande run :

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "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 }}
          cache: "pip"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install .[dev]

Cette étape est tout ce dont vous avez besoin pour installer les dépendances requises. La seule étape restante consiste à exécuter pytest :

name: Run Tests

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master
  workflow_call:
  workflow_dispatch:

jobs:
  testing:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "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 }}
          cache: "pip"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install .[dev]

      - name: Run Pytest
        run: pytest

À ce stade, vous avez à la fois un workflow ling et test qui est déclenché chaque fois qu'un événement PR ou push se produit sur Master. Ensuite, vous tournerez votre attention vers la partie CD de CI/CD et apprendrez comment vous pouvez publier automatiquement un package à PYPI.

Publier automatiquement votre package à PYPI

Le troisième workflow complète ce que la plupart des gens considèrent comme un pipeline CI/CD minimum. Ce troisième flux de travail fournit un moyen reproductible et cohérent de créer et de publier un package. Le package Real Python Reader utilise la bibliothèque Python build largement utilisée pour générer des fichiers de distribution Python, qui peuvent ensuite être déployés sur PyPI.

Lorsque les flux de travail deviennent un peu plus compliqués et comportent plusieurs étapes ou tâches, il est recommandé d’écrire les étapes et le flux. Cela vous aidera à suivre toutes les étapes dans le bon ordre afin que les actions GitHub que vous utilisez soient correctement configurées dès le début. Cela vous fera gagner du temps plus tard en vous aidant à éviter les bugs potentiels dans votre flux de travail de build.

Voici les étapes du workflow pour le fichier deploy.yml :

  1. configurer l'environnement en installant des dépendances Python et construire
  2. Créez le package en plaçant des fichiers de sortie dans un dossier dist/
  3. publier les fichiers de distribution à PYPI
  4. Créez une version GitHub si la publication a réussi

Dans la section suivante, vous aborderez les deux premiers éléments de la liste et que vous aurez une bonne partie de votre workflow écrit.

Configuration et construction du package

Comme pour les deux derniers flux de travail, la première étape consiste à définir les déclencheurs du workflow. Vous avez vu des déclencheurs communs qui tournent autour des workflows de développeur typiques, mais la libération automatique avec chaque nouveau RP ou Push to the Mais-Mraning Branch n'est pas idéal pour le vrai lecteur Python.

Il est plus logique de baisser la version du package après plusieurs demandes de traction, des corrections de bogues ou après avoir ajouté de nouvelles fonctionnalités. La façon moderne de déclencher une telle version après une version de version consiste à utiliser le meilleur ami du développeur, Git.

Git vous permet de baliser un commit pour indiquer un moment notable dans le développement du logiciel. C'est souvent l'outil de choix pour définir une nouvelle version. Les actions GitHub disposent d'une prise en charge intégrée pour l'utilisation des balises Git comme déclencheurs via le mot-clé tags :

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

Comme vous pouvez le voir ici, les déclencheurs prennent également en charge les modèles GLOB. Ainsi, un astérisque ( * ) peut correspondre à n'importe quel caractère dans une séquence. Le modèle décrit ci-dessus correspondra à tout caractère suivi d'un point décimal (. ), un autre caractère, un autre point décimal et enfin, un autre caractère.

Cela signifie que 1.0.0 est une correspondance valide, tout comme 2.5.60. Cela correspond au versioning sémantique utilisé par Real Python Reader. Vous pouvez également utiliser v *. *. * à la place si vous préférez. Ainsi, vos balises GIT doivent commencer par un v , qui signifie version . Par exemple, v1.0.0 serait une balise valide.

Afin de déclencher ce flux de travail, vous marqueriez un engagement avec le nom de la version:

$ git tag -a "1.0.0" -m "1.0.0"
$ git push --tags

Pousser votre nouvelle balise vers GitHub déclenchera alors ce flux de travail. Ensuite, vous allez configurer l’environnement et installer les dépendances :

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

Tout d'abord, vous définissez la tâche publier et installez Python 3.13 dans une machine virtuelle Ubuntu. L'étape suivante installe les dépendances de construction de Real Python Reader. Dans la dernière étape, vous utilisez la même commande run que vous avez utilisée auparavant, mais cette fois, au lieu d'exécuter Ruff ou pytest, vous allez créer le Real Python Reader. emballer. Par défaut, build placera les fichiers de distribution dans un dossier appelé dist.

Excellent! Vous avez mis en œuvre les deux premières parties principales du plan de flux de travail. Avant de pouvoir déployer sur PyPI, vous devez savoir comment sécuriser votre jeton API PyPI.

Garder vos secrets en sécurité

Comme vous l'avez appris plus tôt, les workflows ont accès à des contextes spéciaux comme matrice . Un autre contexte auquel tous les workflows ont accès est le contexte secrets . En stockant des données sensibles en tant que Secointe Secret , vous pouvez vous assurer de ne jamais divulguer accidentellement des clés d'API, des mots de passe ou d'autres informations d'identification. Votre flux de travail peut accéder à ces informations d'identification sensibles à l'aide du contexte secrets .

Vous pouvez ajouter des secrets à votre référentiel sur le site Web de GitHub. Une fois que vous les avez ajoutés, vous ne pouvez pas les voir ou les modifier. Vous ne pouvez les remplacer que par une nouvelle valeur. C'est une bonne idée de revoir la documentation GitHub pour voir comment ajouter des secrets sur le site Web de GitHub. Les documents officiels sont continuellement mis à jour avec tous les modifications de l'interface utilisateur, ce qui en fait la meilleure source pour apprendre à utiliser cette fonctionnalité GitHub.

Déploiement de votre colis

Après avoir sécurisé votre clé API en tant que secret GitHub, vous pouvez y accéder dans le workflow :

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

    - name: Test publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}
        repository-url: https://test.pypi.org/legacy/

    - name: Publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}

Dans cette étape, vous pouvez utiliser l'action GitHub officielle de la Python Packaging Authority (PyPA), qui gère PyPI. Cette action GitHub effectue l'essentiel du travail et n'a besoin que d'une référence à votre jeton API PyPI. Encore une fois, par défaut, il recherchera dans votre dossier dist toute nouvelle version d'un package à télécharger.

Plutôt que d'utiliser un nom d'utilisateur et un mot de passe traditionnels pour s'authentifier auprès de PYPI, il est de la meilleure pratique d'utiliser un jeton API dans le cadre de versions automatiques.

Puisque vous utilisez un jeton API et qu'il n'y a pas de nom d'utilisateur, l'utilisation de __token__ comme nom d'utilisateur indique à l'action GitHub que l'authentification par jeton est utilisée. Tout comme avec la stratégie matricielle précédente, vous pouvez utiliser la notation par points pour accéder au contexte secret, comme dans secrets.PYPI_API_TOKEN.

Le nom du secret stocké dans GitHub n’a pas d’importance, tant qu’il a du sens pour vous. Le secret GitHub est nommé PYPI_API_TOKEN, vous le référencez donc dans le workflow en utilisant ce nom.

Vous avez peut-être remarqué que le flux de travail comprend une étape de test avant de publier le package à PYPI. Cette étape est presque identique à l'étape de publication, avec une différence clé: vous devrez fournir un Repository-URL pour remplacer l'URL par défaut et pousser le package à tester.pypi.org.

L'utilisation de TestPyPi est un excellent moyen de s'assurer que votre package est construit et versé correctement. Il vous permet d'identifier et de résoudre tous les problèmes potentiels qui pourraient causer des problèmes lors de la publication du référentiel PYPI principal.

Si vous suivez votre propre fork du référentiel et avez l'intention de transférer votre version vers PyPI, vous devrez alors mettre à jour le nom du projet avec un nom unique. Si vous ne mettez pas à jour le nom du projet, vous recevrez une erreur HTTP 403 lorsque vous tenterez de le télécharger. En effet, vous n'êtes pas autorisé à publier le package realpython-reader sur PyPI. La mise à jour du nom du projet vous permettra de publier votre propre version.

À titre d'exemple, vous pouvez ajouter votre nom d'utilisateur comme préfixe au nom du projet :

[build-system]
requires      = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "username-realpython-reader"
# ...

Il y a juste une étape de plus du workflow à terminer - créant une version GitHub à promouvoir, puis partager directement la version. Avant de pouvoir le faire, vous découvrirez les variables d'environnement GitHub.

Accéder aux variables d'environnement GitHub

Afin de publier une version dans un repo GitHub, un jeton GitHub est requis. Vous les avez peut-être déjà utilisés si vous avez déjà utilisé l'API GitHub. Étant donné le risque de sécurité d'utiliser des jetons GitHub personnels dans les flux de travail, GitHub crée un jeton en lecture seule dans le contexte des secrets par défaut. Cela signifie que vous y avez toujours accès si vous en avez besoin.

De plus, chaque exécuteur GitHub inclut par défaut la CLI GitHub pratique. Cela rend l'exécution de certaines tâches, comme la création d'une version, beaucoup plus simple. La CLI GitHub propose de nombreuses façons d'authentifier l'utilisateur, dont l'une consiste à définir une variable d'environnement appelée GITHUB_TOKEN.

Vous pouvez voir où cela va. Le jeton GitHub fourni peut être utilisé pour accéder à la CLI et finalement créer un moyen transparent de créer la version github. Voici à quoi cela ressemblerait dans le flux de travail:

name: Publish to PyPI
on:
  push:
    tags:
      - "*.*.*"

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: "3.13"

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install .[build]

    - name: Build package
      run: python -m build

    - name: Test publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}
        repository-url: https://test.pypi.org/legacy/

    - name: Publish package
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        user: __token__
        password: ${{ secrets.PYPI_API_TOKEN }}

    - name: Create GitHub Release
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      run: |
        gh release create ${{ github.ref_name }} ./dist/* --generate-notes

Vous verrez que sur les lignes 39 et 40, le workflow attribue spécifiquement le jeton GitHub du contexte des secrets à une variable d'environnement appelée github_token . Toutes les valeurs de clé définies dans Env seront définies sous forme de variables d'environnement pour l'étape actuelle. Cela signifie que lorsque vous exécutez le GitHub CLI ( gh ), il aura accès au jeton via la variable d'environnement attribuée. Le GitHub CLI ne peut pas accéder directement au contexte des secrets lui-même.

GitHub vous permet également d'accéder à un contexte spécial appelé github . Le workflow fait référence à l'attribut ref_name dans le contexte github . Ceci est défini dans les documents GitHub comme suit:

Le nom de la référence courte de la branche ou de la balise qui a déclenché l'exécution du workflow. (Source)

Ainsi, github.ref_name sera remplacé par l'attribut qui a déclenché le workflow, qui dans ce cas est le nom de la balise GIT.

La commande gh ci-dessus créera une version avec le même nom que la balise utilisée pour déclencher la version, téléchargera tous les fichiers depuis ./dist et générera automatiquement des notes de version. Ces notes de version incluent tous les PR que les développeurs ont fusionnés depuis la création de la dernière version, attribuant ainsi le crédit aux auteurs avec des liens et des noms d'utilisateur pour leurs contributions.

Vous souhaiterez peut-être ajouter les détails manquants aux notes de version. N'oubliez pas que les versions peuvent être modifiées après leur création si vous devez inclure des informations supplémentaires, telles que des avis de dépréciation.

Félicitations! Vous disposez désormais d’un peluchage, de tests et d’un déploiement automatisés. Vous pouvez baliser votre dernier commit et le workflow de déploiement final devrait s'exécuter correctement :

Maintenant que Real Python Reader dispose d'un pipeline CI/CD pour garantir que toutes les futures modifications de la base de code sont robustes et utilisent un code lisible et cohérent, vous pouvez ajouter un flux de travail supplémentaire à Real Python Reader. La cerise sur le gâteau de notre CI/CD, pour ainsi dire.

Dans la section suivante, vous apprendrez comment configurer Dependabot pour automatiser les mises à jour de sécurité et de dépendances.

Automatisation des mises à jour de sécurité et de dépendances

Tout comme le code Python, vos flux de travail GitHub doivent être maintenus et mis à jour. De plus, les bibliothèques sur lesquelles s'appuie le code de Real Python Reader sont en constante évolution et mises à jour, il est donc difficile de suivre et de gérer les dépendances.

Il peut être particulièrement difficile de rester informé des mises à jour de sécurité publiées par vos dépendances si vous ne suivez pas activement le projet sur GitHub ou les médias sociaux. Heureusement, Github a un outil pratique pour aider les deux problèmes. Entrez Deladabot!

Dependabot est un outil d'automatisation qui non seulement vous informera d'une vulnérabilité de sécurité dans vos dépendances mais, s'il est configuré, créera automatiquement un PR pour mettre à jour et résoudre le problème pour vous. Tout ce que vous avez à faire est de consulter le PR automatisé et de fusionner. Avec Dependabot, garder votre package à jour et exempt de vulnérabilités de sécurité connues est simple et rapide, ce qui vous fait gagner du temps que vous pouvez utiliser pour améliorer votre code ou ajouter de nouvelles fonctionnalités.

Vous pouvez configurer Dependabot pour répondre aux besoins de votre projet. Ici, le package Real Python Reader a des exigences assez basiques. Les deux objectifs sont :

  1. Pour être informé lorsqu'une mise à jour de dépendance est disponible.
  2. Pour aider à maintenir les autres flux de travail à jour.

Ces exigences sont définies dans un fichier de configuration appelé dependabot.yml. Contrairement aux autres workflows, le fichier dependabot.yml se trouve dans le dossier .github lui-même, pas dans .github/workflows.

Étant donné que ce fichier ne dure que douze lignes et que vous êtes maintenant plus familier avec la syntaxe YAML, vous pouvez jeter un œil à la configuration finale de la dépendance:

---
version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"

  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

La propriété version est une partie obligatoire du fichier. C’est là que vous définissez la version de DependAbot à utiliser, et la version 2 est la dernière. Une autre section obligatoire est mises à jour . C'est là que va la majeure partie de la configuration. Chaque mise à jour définit l'écosystème du package à vérifier, ainsi que des informations de base concernant le répertoire Delatebot devraient rechercher, ainsi que la fréquence.

Pour la première mise à jour, Dependabot vérifiera les fichiers courants dans lesquels les dépendances pip sont généralement déclarées, tels que requirements.txt, pyproject.toml et autres. . Étant donné que Real Python Reader a un fichier pyproject.toml dans le répertoire racine, Dependabot est invité à y regarder, comme indiqué par la barre oblique ("/").

À quelle fréquence vous souhaitez être informé des mises à jour de dépendance dépend de vous. Chaque projet aura ses propres exigences. Cependant, l'avoir déclaré dans Yaml signifie que si vous trouvez la cadence trop ou pas assez, c'est un changement rapide et simple à faire. Pour l'instant, vous pouvez utiliser hebdomadaire .

Le deuxième élément de la liste des mises à jour concerne github-actions . C'est vrai, DepenBabot vérifiera également les actions GitHub utilisées dans n'importe quel flux de travail dans le dépôt, tel que setup-python , pour les versions plus récentes! Cela rend la suite des dernières versions des actions GitHub automatiquement et est une chose de moins pour vous.

Grâce à cette configuration en place, Detenabot analysera et vérifiera votre référentiel une fois par semaine pour voir s'il y a des mises à jour que vous pouvez faire pour les dépendances ou vos workflows. Il créera un PR avec un correctif automatiquement. Ces PR de DependAbot exécuteront également vos autres workflows pour vous assurer que les modifications de DelaBabot transmettent vos vérifications de liaison et de test. Double victoire!

Étapes suivantes

Il existe de nombreuses autres tâches que vous pouvez automatiser à mesure que votre référentiel augmente, tels que triage de problèmes, étiquetage, gestion de problèmes périmés, ajoutant des examinateurs à PRS , et plus encore.

Gardez également à l’esprit que GitHub Actions n’est qu’un fournisseur de CI/CD. Si votre projet est hébergé sur GitHub, GitHub Actions peut vous simplifier les choses. Si votre code se trouve sur une autre plateforme ou si vous souhaitez essayer des alternatives, voici une courte liste d'autres fournisseurs CI/CD :

  • GitLab
  • Pipelines Azure
  • CercleCI
  • Travis CI

Si vous utilisez déjà l’un de ces fournisseurs ou s’il n’est pas répertorié, n’hésitez pas à le crier dans les commentaires et à partager vos expériences.

Conclusion

Vous savez maintenant comment implémenter un pipeline CI/CD robuste pour un projet Python à l'aide de GitHub Actions. Bien que l'objectif de ce didacticiel soit d'apprendre à ajouter CI/CD à une base de code existante, j'espère que vous en savez maintenant suffisamment pour travailler avec vos propres projets et packages et créer vos propres flux de travail à partir de zéro.

Dans ce tutoriel, vous avez appris à:

  • Utilisez les actions GitHub et les workflows
  • Automatiser libinting, test et déploiement d'un projet Python
  • Identifiants sécurisés utilisés pour l'automatisation
  • Automatiser mises à jour de sécurité et de dépendance

En automatisant ces processus, vous avez considérablement amélioré la maintenabilité et la fiabilité de votre projet. Vous avez maintenant un moyen cohérent d'assurer la qualité du code, d'exécuter des tests et de déployer de nouvelles versions avec une intervention manuelle minimale.

N'oubliez pas que CI/CD est un processus itératif. À mesure que votre projet grandit et évolue, vous devrez peut-être ajuster vos flux de travail ou en ajouter de nouveaux. La flexibilité de GitHub Actions vous permet de vous adapter facilement aux exigences changeantes.

Avec ces outils et pratiques en place, vous êtes bien équipé pour gérer et faire évoluer efficacement vos projets Python.