Skip to main content

Uso de la CLI de GitHub en un ejecutor

Cómo usar características avanzadas de GitHub Actions para la integración continua (CI).

Nota: Actualmente los ejecutores hospedados en GitHub no se admiten en GitHub Enterprise Server. Puede ver más información sobre la compatibilidad futura planeada en GitHub public roadmap.

Información general de ejemplo

En este artículo se usa un flujo de trabajo de ejemplo para mostrar algunas de las principales características de CI de GitHub Actions. Cuando se desencadena este flujo de trabajo, ejecuta automáticamente un script que comprueba si el sitio de GitHub Docs tienen vínculos rotos. Si se encuentran vínculos rotos, el flujo de trabajo usa la CLI de GitHub para crear una incidencia de GitHub con los detalles.

En el diagrama siguiente se muestra una vista general de los pasos del flujo de trabajo y de cómo se ejecutan en el trabajo:

Diagrama general de los pasos del flujo de trabajo

Características que se usan en este ejemplo

El flujo de trabajo de ejemplo muestra las funcionalidades siguientes de GitHub Actions:

CaracterísticaImplementación
Ejecución de un flujo de trabajo a intervalos regulares:schedule

Flujo de trabajo de ejemplo

El flujo de trabajo siguiente lo creó el equipo de ingeniería de documentos de GitHub. Para revisar la versión más reciente de este archivo en el repositorio github/docs, consulta check-all-english-links.yml.

Nota: cada línea de este flujo de trabajo se explica en la sección siguiente en "Descripción del ejemplo".

YAML
name: Check all English links

# **What it does**: This script once a day checks all English links and reports in issues.
# **Why we have it**: We want to know if any links break.
# **Who does it impact**: Docs content.

on:
  workflow_dispatch:
  schedule:
    - cron: '40 19 * * *' # once a day at 19:40 UTC / 11:40 PST

permissions:
  contents: read
  issues: write

jobs:
  check_all_english_links:
    name: Check all links
    if: github.repository == 'github/docs-internal'
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      FIRST_RESPONDER_PROJECT: Docs content first responder
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content
    steps:
      - name: Check out repo's default branch
        uses: actions/checkout@v3
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.13.x
          cache: npm
      - name: npm ci
        run: npm ci
      - name: npm run build
        run: npm run build
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

      # check-english-links.js returns 0 if no links are broken, and 1 if any links
      # are broken. When an Actions step's exit code is 1, the action run's job status
      # is failure and the run ends. The following steps create an issue for the
      # broken link report only if any links are broken, so `if: ${{ failure() }}`
      # ensures the steps run despite the previous step's failure of the job.

      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "::set-output name=title::$(head -1 broken_links.md)"
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"

          # Link to the previous report from the new report that triggered this
          # workflow run.

          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

          # If an old report is open and assigned to someone, link to the newer
          # report without closing the old report.

          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
            fi
          done

          # Link to the newer report from any older report that is still open,
          # then close the older report and remove it from the first responder's
          # project board.

          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

Descripción del ejemplo

En la tabla siguiente se explica cómo se usa cada una de estas características al crear un flujo de trabajo de GitHub Actions.

Código Explicación
YAML
name: Check all English links

El nombre del flujo de trabajo tal como aparecerá en la pestaña "Acciones" del repositorio GitHub.

YAML
on:
  workflow_dispatch:
  schedule:
    - cron: '40 20 * * *' # once a day at 20:40 UTC / 12:40 PST

Define workflow_dispatch y scheduled como desencadenadores para el flujo de trabajo:

  • workflow_dispatch permite ejecutar manualmente este flujo de trabajo desde la interfaz de usuario. Para más información, vea workflow_dispatch.
  • El evento schedule permite usar la sintaxis cron para definir un intervalo regular para desencadenar automáticamente el flujo de trabajo. Para más información, vea schedule.
YAML
permissions:
  contents: read
  issues: write

Modifica los permisos predeterminados concedidos a GITHUB_TOKEN. Esto variará en función de las necesidades del flujo de trabajo. Para obtener más información, consulta "Asignación de permisos a trabajos".

YAML
jobs:

Agrupa todos los trabajos que se ejecutan en el archivo de flujo de trabajo.

YAML
  check_all_english_links:
    name: Check all links

Define un trabajo con el identificador check_all_english_links y el nombre Check all links, que se almacena en la clave jobs.

YAML
if: github.repository == 'github/docs-internal'

El trabajo check_all_english_links solo se ejecuta si el repositorio se denomina docs-internal y está dentro de la organización github. De lo contrario, el trabajo se marca como omitido.

YAML
runs-on: ubuntu-latest

Configura el job para ejecutarse en un ejecutor Ubuntu Linux. Esto significa que el trabajo se ejecutará en una máquina virtual nueva que se hospede en GitHub. Para obtener ejemplos de sintaxis con otros ejecutores, consulta «Sintaxis de flujo de trabajo para GitHub Actions».

YAML
    env:
      GITHUB_TOKEN: ${{ secrets.DOCUBOT_READORG_REPO_WORKFLOW_SCOPES }}
      REPORT_AUTHOR: docubot
      REPORT_LABEL: broken link report
      REPORT_REPOSITORY: github/docs-content

Crea variables de entorno personalizadas y vuelve a definir la variable GITHUB_TOKEN integrada para usar un secreto personalizado. Se hará referencia a estas variables más adelante en el flujo de trabajo.

YAML
    steps:

Agrupa todos los pasos que se ejecutarán como parte del trabajo check_all_english_links. Cada trabajo del flujo de trabajo tiene su propia sección steps.

YAML
      - name: Check out repo's default branch
        uses: actions/checkout@v3

La palabra clave uses le indica al trabajo que recupere la acción denominada actions/checkout. Esta es una acción que revisa tu repositorio y lo descarga al ejecutor, lo que te permite ejecutar acciones contra tu código (tales como las herramientas de prueba). Debes utilizar la acción de verificación cada que tu flujo de trabajo se ejecute contra el código del repositorio o cada que estés utilizando una acción definida en el repositorio.

YAML
      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: 16.8.x
          cache: npm

En este paso, se usa la acción actions/setup-node para instalar la versión especificada del paquete de software node en el ejecutor, lo que te da acceso al comando npm.

YAML
      - name: Run the "npm ci" command
        run: npm ci
      - name: Run the "npm run build" command
        run: npm run build

La palabra clave run indica al trabajo que ejecute un comando en el ejecutor. En este caso, los comandos npm ci y npm run build se ejecutan como pasos independientes para instalar y compilar la aplicación Node.js en el repositorio.

YAML
      - name: Run script
        run: |
          script/check-english-links.js > broken_links.md

Este comando run ejecuta un script que se almacena en el repositorio en script/check-english-links.js y canaliza la salida a un archivo denominado broken_links.md.

YAML
      - if: ${{ failure() }}
        name: Get title for issue
        id: check
        run: echo "::set-output name=title::$(head -1 broken_links.md)"

Si el script check-english-links.js detecta vínculos rotos y devuelve un estado de salida distinto de cero (error), usa un comando de flujo de trabajo para establecer una salida que tenga el valor de la primera línea del archivo broken_links.md (se usa el paso siguiente).

YAML
      - if: ${{ failure() }}
        name: Create issue from file
        id: broken-link-report
        uses: peter-evans/create-issue-from-file@b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e
        with:
          token: ${{ env.GITHUB_TOKEN }}

          title: ${{ steps.check.outputs.title }}
          content-filepath: ./broken_links.md
          repository: ${{ env.REPORT_REPOSITORY }}
          labels: ${{ env.REPORT_LABEL }}

Usa la acción peter-evans/create-issue-from-file para crear una incidencia de GitHub. Este ejemplo se ancla a una versión específica de la acción mediante el SHA b4f9ee0a9d4abbfc6986601d9b1a4f8f8e74c77e.

YAML
      - if: ${{ failure() }}
        name: Close and/or comment on old issues
        env:
          NEW_REPORT_URL: 'https://github.com/${{ env.REPORT_REPOSITORY }}/issues/${{ steps.broken-link-report.outputs.issue-number }}'
        run: |
          gh alias set list-reports "issue list \
                                       --repo ${{ env.REPORT_REPOSITORY }} \
                                       --author ${{ env.REPORT_AUTHOR }} \
                                       --label '${{ env.REPORT_LABEL }}'"
          previous_report_url=$(gh list-reports \
                                  --state all \
                                  --limit 2 \
                                  --json url \
                                  --jq '.[].url' \
                                  | grep -v ${{ env.NEW_REPORT_URL }} | head -1)

          gh issue comment ${{ env.NEW_REPORT_URL }} --body "⬅️ [Previous report]($previous_report_url)"

Usa gh issue list para buscar la incidencia creada previamente a partir de ejecuciones anteriores. Se le asigna el alias gh list-reports para facilitar el procesamiento en pasos posteriores. Para obtener la dirección URL de la incidencia, la expresión jq procesa la salida JSON resultante.

Después, se usa gh issue comment para agregar un comentario a la nueva incidencia que vincula a la anterior.

YAML
          for issue_url in $(gh list-reports \
                                  --json assignees,url \
                                  --jq '.[] | select (.assignees != []) | .url'); do
            if [ "$issue_url" != "$" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report]($)"
            fi
          done

Si una incidencia de una ejecución anterior está abierta y asignada a alguien, usa gh issue comment para agregar un comentario con un vínculo a la nueva incidencia.

YAML
          for issue_url in $(gh list-reports \
                                  --search 'no:assignee' \
                                  --json url \
                                  --jq '.[].url'); do
            if [ "$issue_url" != "${{ env.NEW_REPORT_URL }}" ]; then
              gh issue comment $issue_url --body "➡️ [Newer report](${{ env.NEW_REPORT_URL }})"
              gh issue close $issue_url
              gh issue edit $issue_url --remove-project "${{ env.FIRST_RESPONDER_PROJECT }}"
            fi
          done

Si una incidencia de una ejecución anterior está abierta y no está asignada a nadie, haz lo siguiente:

  • Usa gh issue comment para agregar un comentario con un vínculo a la nueva incidencia.
  • Usa gh issue close para cerrar la incidencia antigua.
  • Usa gh issue edit para editar la incidencia antigua y quitarla de un panel de proyecto específico de GitHub.

Pasos siguientes