Búsqueda de sitios web

Integración e implementación continua para Python con acciones de Github


La creación de software es un logro que vale la pena celebrar. Pero el software nunca es estático. Se deben solucionar errores, las características deben agregarse y la seguridad exige actualizaciones periódicas. En el panorama actual, con metodologías ágiles dominantes, los sistemas de DevOps robustos son cruciales para administrar una base de código en evolución. Ahí es donde brillan las acciones de Github, permitiendo a los desarrolladores de Python para automatizar los flujos de trabajo y garantizar que sus proyectos se adapten a la perfección al cambio.

GitHub Actions para Python permite a los desarrolladores automatizar los flujos de trabajo de manera eficiente. Esto permite a los equipos mantener la calidad del software mientras se adaptan a un cambio constante.

Integración continua e implementación continua (CI/CD) Los sistemas ayudan a producir software bien probado y de alta calidad y despliegue de racionalización. Las acciones de GitHub hacen que CI/CD accesible para todos, lo que permite la automatización y la personalización de los flujos de trabajo directamente en su repositorio. Este servicio gratuito permite a los desarrolladores ejecutar sus procesos de desarrollo de software de manera eficiente, mejorando la productividad y la confiabilidad del código.

En este tutorial, aprenderá a:

  • Utilice acciones de GitHub y flujos de trabajo
  • Automatizar pelusas, pruebas e implementación de un proyecto de Python
  • Credenciales seguras utilizadas para la automatización
  • Automatizar actualizaciones de seguridad y dependencia

Este tutorial utilizará una base de código existente, Real Python Reader, como punto de partida para el que creará una tubería CI/CD. Puede bifurcar el código de lector de Python real en Github para seguir. Asegúrese de anular la selección de la opción Copiar la opción maestro ramificada cuando se bifurca. Alternativamente, si lo prefiere, puede construir su propio lector real de Python utilizando un tutorial anterior.

Para aprovechar al máximo este tutorial, debe sentirse cómodo con pip, crear paquetes de Python, Git y estar familiarizado con la sintaxis de YAML.

Antes de profundizar en las acciones de GitHub, puede ser útil dar un paso atrás y aprender sobre los beneficios de CI/CD. Esto lo ayudará a comprender los tipos de problemas que las acciones de GitHub pueden resolver.

Cómo desbloquear los beneficios de CI/CD

La Integración Continua (CI) y la Implementación Continua (CD), comúnmente conocidas como CI/CD, son prácticas esenciales en el desarrollo de software moderno. Estas prácticas automatizan la integración de cambios de código, la ejecución de pruebas y la implementación de aplicaciones. Esto ayuda a los equipos y a los contribuyentes de código abierto a realizar cambios de código con mayor frecuencia de una manera confiable y estructurada.

Además, al publicar paquetes de Python de código abierto, CI/CD asegurará que todas las solicitudes de extracción (PR) y las contribuciones a su paquete satisfagan las necesidades del proyecto mientras estandarizarán la calidad del código.

Implementaciones más frecuentes con cambios de código más pequeños Reduzca el riesgo de cambios de ruptura no deseados que pueden ocurrir con lanzamientos más grandes y complejos. Por ejemplo, a pesar de que los desarrolladores pueden formatear todo el código utilizando las mismas herramientas y reglas de pelusa, la política puede impedir automáticamente que se fusionen las PRS si las pruebas del código no pasan.

En la siguiente sección, aprenderá cómo los flujos de trabajo de GitHub pueden ayudarlo a implementar CI/CD en un repositorio alojado en GitHub.

Explorando flujos de trabajo de Github

Los flujos de trabajo de GitHub son una característica poderosa de GitHub Actions. Le permiten definir flujos de trabajo de automatización personalizados para sus repositorios. Ya sea que desee compilar, probar o implementar su código, los flujos de trabajo de GitHub brindan una solución flexible y personalizable que cualquier proyecto en GitHub puede usar de forma gratuita, ya sea que el repositorio sea público o privado.

Aunque existen muchos proveedores de CI/CD, GitHub Actions se ha convertido en el predeterminado entre los proyectos de código abierto en GitHub debido a su ecosistema expansivo, flexibilidad y costo bajo o nulo.

Anatomía de un archivo de flujo de trabajo

Los archivos de flujo de trabajo se escriben declarativamente archivos YAML con una estructura predefinida que debe cumplirse para que un flujo de trabajo se ejecute con éxito. Sus archivos de flujo de trabajo YAML se almacenan y definen en una carpeta .github/workflows/ en el directorio raíz de su proyecto.

Su carpeta de flujo de trabajo puede tener varios archivos de flujo de trabajo, cada uno de los cuales realizará una tarea determinada. Puede nombrar estos archivos de flujo de trabajo como desee. Sin embargo, en aras de la simplicidad y la legibilidad, es una práctica común nombrarlos según las tareas que realizan, como test.yml.

Cada archivo tiene algunos elementos obligatorios, pero muchos, muchos más que son opcionales. La documentación de GitHub Actions es exhaustiva y está bien escrita, así que asegúrese de consultarla una vez que haya terminado de leer este tutorial.

Hay tres partes principales que constituyen la mayor parte de un archivo de flujo de trabajo: activadores, trabajos y pasos. Los cubrirá en las siguientes secciones.

Activadores de flujo de trabajo

Un desencadenante es un evento que hace que se ejecute un flujo de trabajo. Hay muchos tipos de desencadenantes. Los más comunes son los que ocurren en A:

  • Solicitud de extracción
  • empujó commit a la rama predeterminada
  • Confirmación etiquetada
  • Gatillo manual
  • Solicitud de otro flujo de trabajo
  • nuevo problema que se abre

También es posible que desee restringir los desencadenantes al limitarlo a una rama o un conjunto de archivos específico. Aquí hay un ejemplo simple de un desencadenante que ejecuta un flujo de trabajo en cualquier empuje a la rama principal:

on:
  push:
    branches:
      - main

Para obtener información detallada sobre los desencadenantes no cubiertos en este tutorial, puede consultar la documentación oficial.

Ahora que sabe cómo los eventos activan los flujos de trabajo, es hora de explorar el siguiente componente de un archivo de flujo de trabajo: los trabajos.

Trabajos de flujo de trabajo

Cada flujo de trabajo tiene una sola sección Jobs , que es el contenedor para la carne y las papas del flujo de trabajo. Un flujo de trabajo puede incluir uno o más trabajos que ejecutará, y cada trabajo puede contener uno o más pasos.

Aquí hay un ejemplo de cómo se vería esta sección sin pasos:

# ...

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

Cuando crea un trabajo, lo primero que debe hacer es definir el ejecutor que desea utilizar para ejecutar su trabajo. Un runner es una máquina virtual (VM) alojada en GitHub que ejecuta sus trabajos por usted. GitHub aprovisionará y desaprovisionará la VM para que usted no tenga que preocuparse por mantener ninguna infraestructura para su CI/CD.

Hay varios sistemas operativos compatibles disponibles. Puede encontrar la lista completa de ejecutores alojados en GitHub en la documentación.

Definir un corredor requiere tan solo una línea 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
    # ...

En el ejemplo anterior, my_first_job se ejecutará dentro de una VM Ubuntu, y my_second_job se ejecutará dentro de una VM de Windows. Ambos usan el sufijo -latest en este caso, pero también puede especificar la versión exacta del sistema operativo, por ejemplo, Ubuntu-20.24 , siempre que sea un compatible con el compatible versión.

Pasos de flujo de trabajo

Los pasos son la parte principal de un trabajo. Como probablemente haya adivinado, los pasos declaran las acciones que deben realizarse al ejecutar el flujo de trabajo. Esto puede incluir tareas como la instalación de Python, ejecutar pruebas, pelcaras su código o usar otra acción de GitHub.

Al igual que el código Python, las tareas comunes y repetibles se pueden abstraer en flujos de trabajo separados y reutilizarse. Esto significa que puedes y debes usar las GitHub Actions de otras personas en tus propios flujos de trabajo, de manera similar a como lo harías al importar una biblioteca de Python, para ahorrarte tiempo al reimplementar esa funcionalidad.

En la siguiente sección, verás cómo puedes usar otras acciones de GitHub y cómo encontrarlas.

Usando acciones de GitHub para Python

Aunque los flujos de trabajo son parte de GitHub Actions, los flujos de trabajo también pueden contener GitHub Actions. En otras palabras, puede utilizar las acciones de otras personas u organizaciones en su flujo de trabajo. De hecho, es una práctica común y muy recomendable utilizar GitHub Actions existentes en sus archivos de flujo de trabajo. Esta práctica le ahorra tiempo y esfuerzo al aprovechar las funcionalidades prediseñadas.

Si tiene una tarea específica que realizar, es probable que haya una acción de GitHub disponible para realizarla. Puede encontrar acciones de GitHub relevantes en GitHub Marketplace, en el que profundizará a continuación.

Explorando el mercado de Github

GitHub Marketplace es un repositorio en línea de todas las acciones que las personas pueden utilizar en sus propios flujos de trabajo. GitHub, proveedores externos e individuos crean y mantienen estas Acciones de GitHub. Cualquiera puede utilizar la plantilla de acción de GitHub para crear su propia acción y alojarla en el mercado.

Esto ha llevado a una amplia gama de acciones de GitHub disponibles para casi todos los tipos de automatización de tareas imaginables. Todas las acciones en el mercado de Github son de código abierto y de forma gratuita.

En la siguiente sección, verás dos acciones de GitHub que usarás para cada proyecto de Python.

Incluir acciones en flujos de trabajo

Cada flujo de trabajo basado en Python que cree necesita no solo consultar su repositorio actual en el entorno de flujo de trabajo, sino también instalar y configurar Python. Afortunadamente, GitHub tiene acciones oficiales de GitHub para ayudar con ambas tareas:

# ...

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

En el ejemplo anterior, puede ver que el primer paso en pasos es usar la acción oficial checkout . Esta acción verifica el código de su repositorio en el espacio de trabajo GitHub actual, lo que permite que su flujo de trabajo acceda a él. El @4 siguiente checkout es un especificador de versión, que indica qué versión de la acción usar. A partir de ahora, la última versión es v4.2.2, por lo que puede consultarla utilizando esta sintaxis para especificar la última versión principal.

El segundo paso de este ejemplo configura Python en el entorno. Nuevamente, este ejemplo utiliza la GitHub Action oficial para hacer esto debido a su soporte y desarrollo continuos. La mayoría de las acciones, si no todas, tienen configuraciones adicionales que puedes agregar al paso.

La documentación de la acción Configurar Python contiene la lista completa de configuraciones. Por ahora, lo mínimo que necesita para instalar Python en su entorno de flujo de trabajo es declarar qué versión de Python desea instalar.

En el paso final del ejemplo, utiliza el comando ejecutar. Este comando le permite ejecutar cualquier comando bash o powershell, dependiendo del ejecutor que esté utilizando para el paso. En este caso, estás instalando las dependencias del proyecto desde el archivo de requisitos.

Con suerte, puedes ver cuán poderosas pueden ser las acciones de Github. Con muy poco código y esfuerzo, tiene una forma reproducible de configurar un entorno listo para construir, probar e implementar su proyecto Python.

Ahora tiene una comprensión básica de la estructura de un archivo de flujo de trabajo y cómo puede crear su primer flujo de trabajo para un proyecto. En la siguiente sección, lo harás con un ejemplo del mundo real.

Creando su primer flujo de trabajo

Es hora de caminar por los pasos de agregar CI/CD a un proyecto existente del mundo real, el verdadero lector de Python. Antes de agregar flujos de trabajo para probar e implementar este paquete, primero debe comenzar con la pelusa.

Un linter es una herramienta que analiza su código y busca errores, problemas estilísticos y construcciones sospechosas. La pelusa le permite abordar los problemas y mejorar la calidad de su código antes de compartirlo con otros. Al comenzar su CI/CD con Linting, se asegurará de que su código esté limpio y legible antes de implementar el paquete en PYPI.

Para este flujo de trabajo, utilizará Ruff para eliminar el código Python. Pero si aún no lo ha hecho, primero bifurque el repositorio, incluidas todas las ramas, y luego clónelo. Asegúrate de reemplazar tu-nombre de usuario con tu nombre de usuario de GitHub:

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

Después de clonar su repositorio bifurcado y cambiar su directorio de trabajo actual, deberá cambiar a la rama preexistente llamada github-actions-tutorial. Si dicha rama no está disponible, lo más probable es que haya olvidado desmarcar la opción Copiar sólo la rama master al realizar la bifurcación. En tal caso, debe eliminar su bifurcación, volver al repositorio original, bifurcarla nuevamente y asegurarse de incluir todas las ramas esta vez.

Una vez que haya cambiado con éxito a la rama correcta, cree una carpeta para almacenar sus flujos de trabajo. Esta carpeta debe llamarse workflows/ y ser un subdirectorio de la carpeta .github/.

Ahora está listo para crear su primer flujo de trabajo en el que definirá sus activadores, configurará el entorno e instalará Ruff. Para comenzar, puede definir sus activadores en el archivo lint.yml:

name: Lint Python Code

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

Aunque no es obligatorio, se considera una buena práctica darle a cada uno de sus flujos de trabajo un nombre claro y legible por humanos. Este nombre aparecerá en la columna izquierda de la pestaña Acciones en su repositorio de GitHub. Le ayuda a identificar los flujos de trabajo disponibles y filtrar sus ejecuciones de flujo de trabajo anteriores:

Después de definir el nombre, puede centrarse en los desencadenantes de este flujo de trabajo. En el código anterior, se definen tres desencadenantes diferentes que pueden iniciar el flujo de trabajo:

  1. Abrir una solicitud de extracción
  2. Impulsar compromisos locales
  3. Distribuir el flujo de trabajo manualmente

Los dos primeros activarán el flujo de trabajo en cualquier evento de solicitud push o pull en la rama master. Esto significa que cualquier cambio en el código activará la ejecución de este flujo de trabajo, ya sea que vaya directamente a master o utilice una solicitud de extracción para fusionar el código en la rama master de su repositorio.

No es obvio lo que hace el disparador final. Según la documentación, se usa comúnmente para volver a ejecutar un flujo de trabajo que falló por razones no relacionadas con los cambios en el código, como una clave API vencida. Sin embargo, el disparador workflow_dispatch solo funciona cuando el archivo de flujo de trabajo está en la rama predeterminada.

Con los desencadenantes definidos, es hora de proceder al siguiente paso para crear el archivo de flujo de trabajo, que es definir los trabajos y configurar el entorno:

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 mayor parte de este código debería parecerle familiar a partir de ejemplos anteriores, pero hay un par de pequeñas diferencias. Primero, nombró el trabajo lint para describir lo que hace. Este es solo un nombre, por lo que puede elegir el nombre que desee siempre que cumpla con la sintaxis YAML. También definiste el ejecutor que usarás para este flujo de trabajo como ubuntu-latest.

Luego, notará que la acción setup-python ahora está configurada para almacenar en caché las dependencias PIP de cualquier paquete instalado. Esto ayuda a acelerar su flujo de trabajo en futuras ejecuciones si las versiones de un paquete son las mismas. En lugar de sacarlos de Pypi, usará las versiones en caché.

Ahora que su flujo de trabajo tiene un disparador y corredor definidos, y con su código de código y Python instalado, es hora de instalar Ruff y ejecutarlo para pintar el código. Puede hacerlo agregando dos pasos más a su trabajo Lint :

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

En los dos últimos pasos del trabajo lint, utiliza el comando run que vio anteriormente. Como parte de la sintaxis YAML, observará un símbolo de barra vertical (|) en la segunda línea. Esto denota una cadena de varias líneas. El comando run interpretará las siguientes líneas como comandos separados y las ejecutará en secuencia.

Después de instalar Ruff, el flujo de trabajo finalmente termina ejecutando Ruff para buscar errores de pelusa. Con este comando, puede especificar que desea que la salida se optimice para ejecutar en una etiqueta github de trabajo con la etiqueta -salida-format .

¡Felicidades! Has completado tu primer flujo de trabajo. Una vez que este flujo de trabajo se comprometa con su repositorio y se empuje, GitHub ejecutará automáticamente este flujo de trabajo de pelucas cuando se cumpla la condición de activación. También puede activar este flujo de trabajo manualmente en cualquier momento en el sitio web de Github. Para hacer esto, diríjase a la pestaña Acciones en su repositorio, seleccione el flujo de trabajo deseado desde el lado izquierdo y luego haga clic en Ejecutar el flujo de trabajo :

Ahora que tiene un flujo de trabajo en su haber y comprende cómo funcionan, es hora de crear uno que ejecute el conjunto de pruebas en Real Python Reader.

Creación de un flujo de trabajo de prueba automatizado

Ahora que ya se ha familiarizado con su primer flujo de trabajo de GitHub, es hora de analizar el que posiblemente será el más importante de todos los flujos de trabajo de este paquete: las pruebas automatizadas.

El Real Python Reader usa pytest como su marco de prueba. Y dado lo que ya ha aprendido sobre las acciones de GitHub, incluso puede ver cómo puede editar el flujo de trabajo de pelusa para convertirlo en un flujo de trabajo de prueba. Después de todo, seguirá los mismos pasos para prepararse para ejecutar pytest . Es importante tener en cuenta que cuando está probando un paquete de software, debe probarlo en todas las versiones compatibles de Python.

Pero primero, como con todos los flujos de trabajo de GitHub, debe declarar los desencadenantes del flujo de trabajo de prueba:

name: Run Tests

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

Gran parte de lo anterior es lo mismo que el flujo de trabajo de pelusa anterior pero con una diferencia: ahora hay un nuevo disparador, workflow_call . Al igual que workflow_dispatch , workflow_call es un desencadenante predefinido que permite que otros flujos de trabajo activen este flujo de trabajo.

Esto significa que si tiene un flujo de trabajo en el futuro que también requiere que las pruebas pasen, en lugar de repetir el código, puede pedirle al nuevo flujo de trabajo que use este flujo de trabajo de prueba. El flujo de trabajo activará este flujo de trabajo de prueba como uno de sus pasos y se asegurará de que pase antes de pasar a los otros pasos del trabajo. Así que no más repetición, y puede mantener sus flujos de trabajo más cortos y al grano.

Aunque no utilizarás este método de reutilización del flujo de trabajo en tu flujo de trabajo test.yml, lo lograrás de la misma manera que llamas a otras acciones de GitHub en tu archivo de flujo de trabajo, usando el comando . utiliza la palabra clave:

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

Aquí, puede ver que puede reutilizar un flujo de trabajo pasando una cadena tipo ruta a usa . Debería comenzar con el nombre de usuario y el nombre del repositorio de GitHub, seguido de la ruta al archivo de flujo de trabajo que desea usar. @master le dice al nuevo flujo de trabajo que desea usar la versión del flujo de trabajo de prueba desde la rama maestro . Y ahora, puedes ver cuán poderosas pueden ser las acciones de GitHub. Reutilizar los flujos de trabajo es una gran ventaja de las acciones de GitHub.

Ahora que ha definido los desencadenantes del flujo de trabajo de prueba, es hora de abordar la pregunta: ¿Cómo se prueban varias versiones de Python? En la siguiente sección, verá cómo puede definir sus pasos una vez y ejecutarlos varias veces, y cada ejecución se realizará en una versión diferente de Python.

Prueba en múltiples versiones de Python

En el flujo de trabajo de linting, usaste la acción setup-python en tus pasos para configurar Python 3.13 en la instancia de Ubuntu, que se veía así:

# ...

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

Desafortunadamente, no puedes simplemente agregar una lista de versiones de Python a python-version y listo. Lo que necesita es una matriz strategy para probar en múltiples versiones de Python.

Para citar la documentación oficial:

Una estrategia de matriz le permite usar variables en una definición de trabajo única para crear automáticamente múltiples ejecuciones de trabajo que se basan en las combinaciones de las variables. Por ejemplo, puede usar una estrategia de matriz para probar su código en múltiples versiones de un idioma o en múltiples sistemas operativos. (Fuente)

En resumen, las variables que defina en su matriz ejecutará los mismos pasos en el trabajo, pero usando esas variables. Aquí, desea ejecutar en diferentes versiones de Python, pero también puede usar esto para ejecutar o construir su código en diferentes sistemas operativos.

Declarar una estrategia es relativamente sencillo. Antes de definir sus pasos pero como parte de su trabajo, puede definir su estrategia requerida:

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"]

Como puede ver, está declarando una variable Python-Version , que es una matriz de números de versión. ¡Genial, esta es la primera parte hecha! La segunda parte es decir la acción setup-python que desea usar estas versiones utilizando una sintaxis de variable especial:

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"

El paso de configuración de Python del flujo de trabajo ahora tiene dos cambios. El primero es el nombre agregado al paso. Como aprendió anteriormente, esto no es necesario, pero le ayudará a identificar qué versión de Python falló haciendo referencia a la versión de Python en el nombre del paso. Esto es útil, dado que este paso se ejecutará para cinco versiones diferentes de Python.

El segundo cambio es que en lugar de codificar el número de versión en la parte with: python-version de setup-python, ahora puede consultar la parte python- versión definida en la matriz.

GitHub tiene algunos contextos especiales a los que puede acceder como parte de sus flujos de trabajo. Matrix es uno de ellos. Al definir la matriz como parte de la estrategia, python-version ahora se ha convertido en una propiedad del contexto de la matriz. Esto significa que puede acceder a cualquier variable definida como parte de la matriz con la sintaxis de punto (.), por ejemplo, matrix.python-version.

Aunque esto no es algo que debe hacerse para el Real Python Reader, podría hacer lo mismo con diferentes versiones del sistema operativo. Por ejemplo:

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

Luego puede usar la misma notación de puntos para acceder a la variable OS que definió en la matriz con matrix.os .

Ahora que sabe cómo usar una matriz para ejecutar sus pasos declarativamente utilizando una versión diferente de Python, es hora de completar el flujo de trabajo de prueba en su totalidad.

Finalizando el flujo de trabajo de prueba

Solo se necesitan algunos pasos más para finalizar el flujo de trabajo. Ahora que Python está instalado, el flujo de trabajo deberá instalar las dependencias del desarrollador y luego, finalmente, ejecutar pytest.

El paquete Real Python Reader utiliza un archivo de configuración pyproject.toml para declarar sus dependencias. También tiene dependencias de desarrollador opcionales, que incluyen pytest. Puede instalarlos de la misma manera que instaló Ruff anteriormente, usando el comando 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]

Este paso es todo lo que necesita para instalar las dependencias requeridas. El único paso restante es ejecutar 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

En este punto, tiene un flujo de trabajo de pelusa y prueba que se activan cada vez que ocurre un evento PR o Push en Master. A continuación, centrará su atención en la parte de CD de CI/CD, y aprenderá cómo puede publicar automáticamente un paquete a PYPI.

Publicar su paquete automáticamente en PyPI

El tercer flujo de trabajo completa lo que la mayoría de la gente considera un proceso mínimo de CI/CD. Este tercer flujo de trabajo proporciona una forma reproducible y coherente de crear y publicar un paquete. El paquete Real Python Reader utiliza la biblioteca Python build ampliamente utilizada para generar archivos de distribución de Python, que luego se pueden implementar en PyPI.

Cuando los flujos de trabajo se vuelven un poco más complicados y tienen múltiples pasos o trabajos, se recomienda escribir los pasos y el flujo. Esto te ayudará a seguir todos los pasos en el orden correcto para que las GitHub Actions que utilices estén configuradas correctamente desde el principio. Esto le ahorrará tiempo más adelante al ayudarle a evitar posibles errores en su flujo de trabajo de compilación.

Estos son los pasos del flujo de trabajo para el archivo deploy.yml:

  1. Configurar el entorno instalando dependencias de Python y Build
  2. construya el paquete colocando archivos de salida en una carpeta dist/
  3. Publicar los archivos de distribución en PyPI
  4. Crear una versión de GitHub si se publica con éxito

En la siguiente sección, abordará los dos primeros elementos de la lista y tendrá una buena parte de su flujo de trabajo escrito.

Configurar y construir el paquete

Al igual que con los dos flujos de trabajo anteriores, el primer paso es definir los desencadenantes del flujo de trabajo. Ha visto algunos desencadenantes comunes que giran en torno a los flujos de trabajo típicos de los desarrolladores, pero la liberación automática con cada nuevo PR o envío a la rama principal no es ideal para Real Python Reader.

Tiene más sentido actualizar la versión del paquete después de varias solicitudes de extracción, correcciones de errores o después de agregar nuevas funciones. La forma moderna de desencadenar un lanzamiento de este tipo después de un aumento de versión es utilizar el mejor amigo del desarrollador, Git.

Git le permite etiquetar un compromiso para denotar un punto notable en el tiempo en el desarrollo del software. Esta es a menudo la herramienta de elección para definir una nueva versión. Las acciones de GitHub tienen soporte incorporado para usar etiquetas Git como desencadenantes a través de las etiquetas Palabra clave:

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

Como puede ver aquí, los desencadenantes también admiten patrones de globas. Entonces, un asterisco (*) puede coincidir con cualquier carácter en una secuencia. El patrón descrito anteriormente coincidirá con cualquier carácter seguido de un punto decimal (. ), otro carácter, otro punto decimal y, finalmente, otro carácter.

Esto significa que 1.0.0 es una coincidencia válida, al igual que 2.5.60. Esto coincide con el control de versiones semántico utilizado por Real Python Reader. También puedes usar v*.*.* en su lugar si lo prefieres. Por lo tanto, sus etiquetas Git deben comenzar con v, que significa versión. Por ejemplo, v1.0.0 sería una etiqueta válida.

Para activar este flujo de trabajo, etiquetaría una confirmación con el nombre de la versión:

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

Al enviar su nueva etiqueta a GitHub, se activará este flujo de trabajo. A continuación, configurará el entorno e instalará las dependencias:

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

Primero, define el trabajo Publicar e instalar Python 3.13 en una VM Ubuntu. El siguiente paso instala las dependencias de compilación del Real Python Reader. En el último paso, usa el mismo comando run que ha usado antes, pero esta vez, en lugar de ejecutar ruff o pytest , construirá el lector real de Python paquete. De forma predeterminada, build colocará los archivos de distribución en una carpeta llamada dist .

¡Excelente! Ha implementado las dos primeras partes principales del plan de flujo de trabajo. Antes de poder implementar en PyPI, debe saber cómo mantener seguro su token de API de PyPI.

Mantener tus secretos seguros

Como aprendiste anteriormente, los flujos de trabajo obtienen acceso a contextos especiales como matrix. Otro contexto al que todos los flujos de trabajo tienen acceso es el contexto secrets. Al almacenar datos confidenciales como un secreto de repositorio, puede asegurarse de no filtrar accidentalmente claves API, contraseñas u otras credenciales. Su flujo de trabajo puede acceder a esas credenciales confidenciales utilizando el contexto secrets.

Puede agregar secretos a su repositorio en el sitio web de GitHub. Una vez que los haya agregado, no podrá verlos ni editarlos. Sólo puedes reemplazarlos con un nuevo valor. Es una buena idea revisar la documentación de GitHub para ver cómo agregar secretos en el sitio web de GitHub. Los documentos oficiales se actualizan continuamente con cualquier cambio en la interfaz de usuario, lo que los convierte en la mejor fuente para aprender a utilizar esta función de GitHub.

Implementación de su paquete

Después de proteger su clave API como secreto de GitHub, puede acceder a ella en el flujo de trabajo:

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 }}

En este paso, puedes usar la acción oficial de GitHub de la Autoridad de Empaque de Python (PYPA), que administra PYPI. Esta acción de GitHub realiza la mayor parte del trabajo y solo necesita una referencia a su token PYPI API. Nuevamente, de forma predeterminada, se verá en su carpeta dist para cualquier versión nueva de un paquete a cargar.

En lugar de utilizar un nombre de usuario y contraseña tradicionales para autenticarse en PyPI, es una buena práctica utilizar un token de API con ámbito para lanzamientos automáticos.

Dado que está utilizando un token API y no hay nombre de usuario, utilizando __ token __ Como el nombre de usuario le dice a la acción de GitHub que se está utilizando la autenticación del token. Al igual que con la estrategia de matriz anterior, puede usar la notación DOT para acceder al contexto secreto, como en secrets.pypi_api_token .

El nombre del secreto cuando se almacena en GitHub no importa, siempre que tenga sentido para usted. El secreto de GitHub se llama PYPI_API_TOKEN, por lo que puedes hacer referencia a él dentro del flujo de trabajo usando ese nombre.

Es posible que haya notado que el flujo de trabajo incluye un paso de prueba antes de publicar el paquete en PyPI. Este paso es casi idéntico al paso de publicación, con una diferencia clave: deberá proporcionar una repository-url para anular la URL predeterminada y enviar el paquete a test.pypi.org.

El uso de TestPypi es una excelente manera de garantizar que su paquete esté construido y versado correctamente. Le permite identificar y abordar cualquier problema potencial que pueda causar problemas al publicar en el repositorio PYPI principal.

Si está siguiendo su propia bifurcación del repositorio y tiene la intención de enviar su versión a PyPI, deberá actualizar el nombre del proyecto a un nombre único. Si no actualiza el nombre del proyecto, recibirá un error HTTP 403 al intentar cargarlo. Esto se debe a que no tiene permiso para publicar el paquete realpython-reader en PyPI. Actualizar el nombre del proyecto le permitirá publicar su propia versión.

Como ejemplo, podrías agregar tu nombre de usuario como prefijo al nombre del proyecto:

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

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

Solo queda un paso más del flujo de trabajo por completar: crear una versión de GitHub para promocionar y luego compartir la versión directamente. Antes de que puedas hacer esto, aprenderás sobre las variables de entorno de GitHub.

Accediendo a las variables de entorno de GitHub

Para publicar una versión en un repositorio de GitHub, se requiere un token de GitHub. Es posible que los haya usado antes si alguna vez usó la API de GitHub. Dado el riesgo de seguridad que supone el uso de tokens personales de GitHub en flujos de trabajo, GitHub crea un token de solo lectura en el contexto de secretos de forma predeterminada. Esto significa que siempre tendrás acceso a él si lo necesitas.

Además, cada corredor de GitHub incluye la práctica GitHub CLI de forma predeterminada. Esto hace que realizar ciertas tareas, como crear una versión, mucho más simple. La CLI GitHub tiene muchas formas de autenticar al usuario, una de las cuales es establecer una variable de entorno llamada github_token .

Puede ver a dónde va esto. El token GitHub proporcionado se puede utilizar para acceder a la CLI y, en última instancia, crear una forma perfecta de crear la versión de GitHub. Así es como se vería eso en el flujo de trabajo:

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

Verá que en las líneas 39 y 40, el flujo de trabajo asigna específicamente el token de GitHub del contexto secreto a una variable de entorno llamada GITHUB_TOKEN. Cualquier valor clave establecido en env se establecerá como variable de entorno para el paso actual. Esto significa que cuando ejecute la CLI de GitHub (gh), tendrá acceso al token a través de la variable de entorno asignada. La CLI de GitHub no puede acceder directamente al contexto de secretos.

GitHub también le permite acceder a un contexto especial llamado GitHub . El flujo de trabajo hace referencia al atributo ref_name en el contexto github . Esto se define en los documentos de GitHub de la siguiente manera:

El nombre de referencia corto de la rama o etiqueta que desencadenó la ejecución del flujo de trabajo. (Fuente)

Entonces, github.ref_name será reemplazado con el atributo que desencadenó el flujo de trabajo, que en este caso es el nombre de la etiqueta Git.

El comando gh anterior creará una versión con el mismo nombre que la etiqueta utilizada para activar la versión, cargará todos los archivos desde ./dist y generará automáticamente notas de la versión. Estas notas de la versión incluyen cualquier RP que los desarrolladores hayan fusionado desde que crearon la última versión, dando el crédito adecuado a los autores con enlaces y nombres de usuario por sus contribuciones.

Es posible que desee agregar los detalles que faltan a las notas de la versión. Recuerde que las versiones se pueden editar después de su creación si necesita incluir información adicional, como avisos de obsolescencia.

¡Felicidades! Ahora tiene implementado el linting, las pruebas y la implementación automatizados. Puede etiquetar su última confirmación y el flujo de trabajo de implementación final debería ejecutarse correctamente:

Ahora que el Real Python Reader tiene una tubería de CI/CD para garantizar que cualquier cambio de base de código futuro sea robusto y use un código legible y consistente, puede agregar un flujo de trabajo más al lector real de Python. La cereza en la parte superior de nuestro pastel CI/CD, por así decirlo.

En la siguiente sección, aprenderá cómo configurar dependAbot para automatizar las actualizaciones de seguridad y dependencia.

Automatizar las actualizaciones de seguridad y dependencia

Al igual que el código Python, sus flujos de trabajo de GitHub deben mantenerse y mantenerse actualizados. Además, las bibliotecas en las que se basa el código de Real Python Reader siempre cambian y se actualizan, por lo que es difícil mantenerse al día y gestionar las dependencias.

Puede ser particularmente difícil mantenerse informado sobre las actualizaciones de seguridad publicadas por sus dependencias si no está siguiendo activamente el proyecto en GitHub o en las redes sociales. Afortunadamente, Github tiene una herramienta útil para ayudar con ambos problemas. ¡Entra dependabot!

Dependabot es una herramienta de automatización que no solo le notificará una vulnerabilidad de seguridad en sus dependencias, sino que, si está configurado, creará automáticamente un PR para actualizar y solucionar el problema para usted. Todo lo que tiene que hacer es revisar las relaciones públicas automatizadas y fusionar. Con DependAbot, mantener su paquete actualizado y libre de vulnerabilidades de seguridad conocidas es rápido y fácil, ahorrándole tiempo que puede usar para mejorar su código o agregar nuevas funciones.

Puede configurar dependabot para satisfacer las necesidades de su proyecto. Aquí, el paquete Real Python Reader tiene requisitos bastante básicos. Los dos goles son:

  1. Para ser notificado cuando hay una actualización de dependencia disponible.
  2. Para ayudar a mantener actualizados los demás flujos de trabajo.

Estos requisitos se definen en un archivo de configuración llamado dependabot.yml . A diferencia de los otros flujos de trabajo, el archivo dependabot.yml vive en la carpeta .github en sí, no en .github/workflows .

Debido a que este archivo tiene solo doce líneas y ahora está más familiarizado con la sintaxis YAML, puede echar un vistazo a la configuración final del Dependabot:

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

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

La propiedad version es una parte obligatoria del archivo. Aquí es donde definirás la versión de Dependabot que usarás, y la versión 2 es la más reciente. Otra sección obligatoria es actualizaciones. Aquí es donde va la mayor parte de la configuración. Cada actualización define el ecosistema de paquetes a verificar, junto con información básica sobre en qué directorio debe buscar el Dependabot, así como con qué frecuencia.

Para la primera actualización, Dependabot comprobará los archivos comunes donde normalmente se declaran las dependencias de pip, como requirements.txt, pyproject.toml y otros. . Dado que Real Python Reader tiene un archivo pyproject.toml en el directorio raíz, se le indica al Dependabot que busque allí, como lo indica la barra diagonal ("/").

Con qué frecuencia desea que se le notifique las actualizaciones de dependencia depende de usted. Cada proyecto tendrá sus propios requisitos. Sin embargo, tenerlo declarado en Yaml significa que si encuentra la cadencia demasiado, o no lo suficiente, es un cambio rápido y simple de hacer. Por ahora, puede usar Weekly .

El segundo elemento en la lista actualizaciones es para github-actions. Así es, Dependabot también verificará las acciones de GitHub utilizadas en cualquier flujo de trabajo en el repositorio, como setup-python, para obtener versiones más recientes. Esto hace que mantenerse al día con las últimas versiones de GitHub Actions sea automático y es una cosa menos de la que preocuparse.

Con esta configuración en su lugar, dependabot escaneará y verificará su repositorio una vez por semana para ver si hay alguna actualización que pueda hacer a las dependencias o sus flujos de trabajo. Creará un PR con una solución automáticamente. Estos PR de dependabot también ejecutarán sus otros flujos de trabajo para asegurarse de que los cambios de dependabot pasen sus verificaciones de pelusa y pruebas. ¡Doble victoria!

Próximos pasos

Hay muchas otras tareas que puede automatizar a medida que su repositorio crece, como clasificación de problemas, etiquetado, gestión de problemas obsoletos, agregar revisores a los RP y más.

Además, tenga en cuenta que GitHub Actions es solo un proveedor de CI/CD. Si su proyecto está alojado en GitHub, GitHub Actions puede simplificarle las cosas. Si su código está en otra plataforma o desea probar alternativas, aquí tiene una breve lista de otros proveedores de CI/CD:

  • Gitlab
  • Tuberías de Azure
  • CírculoCI
  • Travis CI

Si ya usa uno de estos proveedores o uno que no está en la lista, no dude en gritarlo en los comentarios y compartir sus experiencias.

Conclusión

Ahora sabe cómo implementar una canalización de CI/CD sólida para un proyecto de Python utilizando GitHub Actions. Si bien el objetivo de este tutorial era que usted aprendiera cómo agregar CI/CD a una base de código existente, esperamos que ahora sepa lo suficiente para trabajar con sus propios proyectos y paquetes y crear sus propios flujos de trabajo desde cero.

En este tutorial, aprendiste a:

  • Use las acciones github y flujos de trabajo
  • Automatizar linting, pruebas e implementación de un proyecto Python
  • Credenciales seguras utilizadas para la automatización
  • Automatizar actualizaciones de seguridad y dependencia

Al automatizar estos procesos, ha mejorado significativamente la mantenibilidad y la confiabilidad de su proyecto. Ahora tiene una forma consistente de garantizar la calidad del código, ejecutar pruebas e implementar nuevas versiones con una intervención manual mínima.

Recuerde que CI/CD es un proceso iterativo. A medida que su proyecto crece y evoluciona, es posible que deba ajustar sus flujos de trabajo o agregar otros nuevos. La flexibilidad de las acciones de GitHub le permite adaptarse fácilmente a los requisitos cambiantes.

Con estas herramientas y prácticas implementadas, estará bien equipado para administrar y escalar sus proyectos Python de manera eficiente.