Hoy empiezo con GitHub Actions

Llevo varios días jugando con GitHub Actions, haciendo pruebas de diferentes escenarios que me he podido encontrar en otras herramientas de automatización, como Azure DevOps o Jenkins. En este artículo quiero contarte lo mínimo que deberías de saber para comenzar a gestionar con esta plataforma tus tareas de integración y despliegue continuos.

Nueva sección Actions en GitHub

Es posible que si ya trabajabas con GitHub te hayas dado cuenta de que, desde hace un tiempo, tienes una nueva sección llamada Actions.

En ella verás que existen diferentes plantillas para distintos lenguajes de programación llamadas workflows, las cuales te dan un punto de partida para la integración o el despliegue continuo de tus aplicaciones. Puedes explorar aquellas con las que te sientas más a gusto, en cuanto a tecnología, pero quiero enseñarte algo más elaborado en un solo vistazo 🙂

Estructura de un workflow

Si has hecho clic en alguna de las plantillas propuestas en el apartado Actions, verás que GitHub basa sus flujos en archivos en YAML. Cuando guardas cualquiera de estas plantillas estas se almacenan en .github/workflows.

Para poder explicarte mejor la estructura que debes utilizar voy a mostrártelo con este ejemplo, que compila y despliega una aplicación de ejemplo con .NET Core (y Blazor), que proviene del curso Blazor: Getting Started por Gill Cleeren, en Azure App Service:

name: Build and deploy the web app

on:
  push:
    branches:
      - master
    paths: 
      - 'BethanysPieShopHRM.server/**'
      - '.github/workflows/build-and-deploy-web-app.yml'

env:
  WEB_APP_NAME: bethanyspieshopblazor

jobs:
  continuous-integration: #name of the job
    runs-on: windows-latest
    steps:
    - uses: actions/[email protected]
    - name: Set up .NET Core
      uses: actions/[email protected]
      with:
        dotnet-version: '3.0.103'
    - name: Build with dotnet
      run: dotnet build --configuration Release
    - name: dotnet publish
      run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp
      working-directory: ./BethanysPieShopHRM.server
    - name: Upload artifact
      uses: actions/[email protected]
      with:
        name: webapp-artifact
        path: ${{env.DOTNET_ROOT}}/webapp  
  
  continuous-deployment:
    needs: [continuous-integration]
    runs-on: windows-latest
    steps:
    - name: Download artifact
      uses: actions/[email protected]
      with:
        name: webapp-artifact
        path: ${{env.DOTNET_ROOT}}/webapp
    - name: Login via Azure CLI
      uses: azure/[email protected]
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS_BLAZOR_RG }}        
    - name: Add some settings
      uses: azure/[email protected]
      with:
        app-name: ${{env.WEB_APP_NAME}}        
        app-settings-json: '${{ secrets.APP_SETTINGS_WEB_APP_WINDOWS }}' 
    - name: Deploy to Azure Web App
      uses: azure/[email protected]
      with:
        app-name: ${{env.WEB_APP_NAME}}
        slot-name: 'production'
        #publish-profile: ${{ secrets.WebAppPublishProfile }}
        package: ${{env.DOTNET_ROOT}}/webapp
    - name: Azure logout
      run: |
       az logout  

Como puedes ver en el código anterior, un workflow tiene 4 partes fundamentales: un nombre, un evento/s que lo dispara, la declaración de variables de entorno (opcional) y los trabajos que se ejecutarán. Veamos cada apartado por separado:

name

Se trata del nombre del workflow, con el fin de poder diferenciarlo de otros flujos que tengas en el mismo repositorio.

name: Build and deploy the web app

Según la lista va creciendo es muy útil tener un nombre identificativo para cada uno.

Actions – El nombre de los workflows deberían de ser descriptivos

on

Esta propiedad es fundamental, ya que se utilizará para indicar en base a qué se lanzará este flujo.

on:
  push:
    branches:
      - master
    paths: 
      - 'BethanysPieShopHRM.server/**'
      - '.github/workflows/build-and-deploy-web-app.yml'

Como ves, el mismo puede ejecutarse gracias al evento push, entre muchos otros que ya te contaré, sobre ramas específicas (branches), e incluso puede depender también de los cambios que se hayan producido en las rutas especificadas a través de paths. En este ejemplo, el flujo sólo se lanzará para la rama master, pero solo cuando haya ocurrido algún cambio o bien en el propio archivo del workflow o bien en alguno de los archivos dentro del directorio BethanysPieShopHRM.server.

env

Esta sección no es obligatoria pero es muy útil para declarar variables de entorno, que estarán disponibles a nivel global mientras dure el flujo, incluso entre diferentes agentes.

env:
  WEB_APP_NAME: bethanyspieshopblazor

jobs

Como su propio nombre indica, en este apartado se definirán los diferentes trabajos que componen el flujo. Cada uno de ellos tendrá un nombre, runs-on identifica el tipo de runner (agente) que necesita para ejecutar las tareas y una serie de pasos (steps) que se van a llevar a cabo como parte del trabajo.

jobs:
  continuous-integration: #name of the job
    runs-on: windows-latest
    steps:
    - uses: actions/[email protected]
    - name: Set up .NET Core
      uses: actions/[email protected]
      with:
        dotnet-version: '3.0.103'
    - name: Build with dotnet
      run: dotnet build --configuration Release
    - name: dotnet publish
      run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/webapp
      working-directory: ./BethanysPieShopHRM.server
    - name: Upload artifact
      uses: actions/[email protected]
      with:
        name: webapp-artifact
        path: ${{env.DOTNET_ROOT}}/webapp  

Dentro de cada uno de los pasos se pueden ver diferentes acciones: aquellas ejecutadas a través de run, las cuales son comandos sin más, o aquellas que utilizan acciones ya predefinidas, a través de uses. En este fragmento se utilizan varias:

actions/[email protected]: permite obtener una copia del código fuente del repositorio sobre la que trabajar.

actions/[email protected]: se utiliza para crear artefactos en base a archivos o directorios que se especifiquen en dicha acción. Normalmente se utilizan para que otro job pueda descargarlo y hacer uso de él. En este ejemplo se genera un artefacto con el resultado de la compilación del proyecto. Siempre que trabajes con artefactos podrás verlos, y descargarlos, en la sección Artifacts del workflow.

GitHub Actions – Artifacts

Por último, fíjate en el segundo job:

continuous-deployment:
    needs: [continuous-integration]
    runs-on: windows-latest
    steps:
    - name: Download artifact
      uses: actions/[email protected]
      with:
        name: webapp-artifact
        path: ${{env.DOTNET_ROOT}}/webapp
    - name: Login via Azure CLI
      uses: azure/[email protected]
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS_BLAZOR_RG }}        
    - name: Add some settings
      uses: azure/[email protected]
      with:
        app-name: ${{env.WEB_APP_NAME}}        
        app-settings-json: '${{ secrets.APP_SETTINGS_WEB_APP_WINDOWS }}' 
    - name: Deploy to Azure Web App
      uses: azure/[email protected]
      with:
        app-name: ${{env.WEB_APP_NAME}}
        slot-name: 'production'
        #publish-profile: ${{ secrets.WebAppPublishProfile }}
        package: ${{env.DOTNET_ROOT}}/webapp
    - name: Azure logout
      run: |
       az logout  

Este se va a encargar del despliegue. Para que esto sea posible va a depender del job anterior, el cual genera el paquete a desplegar. Las dependencias de otros jobs se establecen con la propiedad needs, donde puedes especificar uno o varios jobs por los cuales este debe esperar para poder ejecutarse. De no indicar nada ambos jobs se ejecutarían en paralelo, por lo que este último fallaría al no estar el artefacto listo.

Aquí se utilizan otras acciones diferentes al anterior:

actions/[email protected]: te permite descargar el artefacto generado en el job anterior.

azure/[email protected]: inicia sesión a través de Azure CLI en tu suscripción de Microsoft Azure, ya que en este ejemplo el despliegue se hará en un App Service.

azure/[email protected]: añade valores en la configuración de este servicio de Azure (depende de la acción anterior, ya que necesitas iniciar sesión antes).

azure/[email protected]: hace propiamente el despliegue. En este ejemplo he dejado comentada la posibilidad de realizar el mismo utilizando la opción publish-profile. Si no necesitaras la tarea anterior, que añade configuración en el servicio, se puede utilizar el perfil de publicación en lugar de Azure CLI.

Estas dos últimas acciones, además de utilizar variables de entorno, también están haciendo uso de secretos: secrets.AZURE_CREDENTIALS_BLAZOR_RG y secrets.APP_SETTINGS_WEB_APP_WINDOWS. Estos se configuran en el apartado Settings del repositorio, en la sección Secrets:

GitHub – Secrets

Una vez guardados en esta sección no será posible volver a visualizar su contenido.

Cada vez que se inicie el workflow, en este caso debido al evento push, podrás ver en tiempo real la ejecución del mismo, seleccionándolo en el apartado Actions. También puedes revisar cada uno de los pasos definidos , incluso cuando la ejecución ya haya finalizado.

Revisar la ejecución de un workflow

Acciones predefinidas para tus workflows

Como has podido ver en el ejemplo, los workflows (flujos) están compuestos de jobs (trabajos) y estos están compuestos de steps (pasos). Si bien podrías definir todos los pasos utilizando scripting, existe un marketplace con más de 3.500 acciones que puedes utilizar para tus flujos.

GitHub Marketplace

¡Saludos!