Skip to main content

Automatización de Projects mediante acciones

Puedes usar GitHub Actions para automatizar los proyectos.

Flujos de trabajo de GitHub Actions

Esta sección demuestra cómo utilizar la API de GraphQL y las GitHub Actions para agregar una solicitud de cambios a un proyecto organizacional. En los flujos de trabajo de ejemplo, cuando la solicitud de cambios se marca como "lista para revisión", se agrega una tarea nueva al proyecto con un campo de "Estado" configurado en "Pendiente" y se agrega la fecha actual a un campo personalizado de "Fecha en la que se publicó".

Puedes copiar uno de los siguientes flujos de trabajo y modificarlo de acuerdo con lo descrito en la siguiente tabla para que satisfaga tus necesidades.

Un proyecto puede abarcar repositorios múltiples, pero un flujo de trabajo es específico par aun repositorio. Agregue el flujo de trabajo a cada repositorio del que quiera que realice un seguimiento el proyecto. Para obtener más información sobre cómo crear archivos de flujo de trabajo, vea "Inicio rápido para GitHub Actions".

Este artículo asume que tienes un entendimiento básico de las GitHub Actions. Para obtener más información sobre GitHub Actions, vea "GitHub Actions".

Para obtener más información sobre otros cambios que puede realizar en el proyecto mediante la API, consulte "Uso de la API para administrar proyectos".

También puedes usar el flujo de trabajo actions/add-to-project, que mantiene GitHub y agregará la incidencia o solicitud de incorporación de cambios actual al proyecto especificado. Para más información, consulta el repositorio actions/add-to-project y el archivo LÉAME.

Nota: GITHUB_TOKEN tiene como ámbito el nivel de repositorio y no puede acceder a projects. Para acceder a projects, puedes crear una instancia de GitHub App (recomendado para proyectos de la organización) o un token de acceso personal (recomendado para proyectos de usuario). A continuación se muestran los ejemplos de flujo de trabajo para ambos acercamientos.

Flujo de trabajo ejemplo autenticándose con una GitHub App

  1. Crea una GitHub App o elige una GitHub App existente que le pertenezca a tu organización. Para obtener más información, vea "Creación de una GitHub App".

  2. Dale a tu GitHub App permisos de lectura y escritura para los proyectos organizacionales. Para obtener más información, vea "Edición de permisos de una GitHub App".

    Nota: Puede controlar el permiso de la aplicación para los proyectos de la organización y para los proyectos del repositorio. Debes otorgar permisos de lectura y escritura de proyectos organizacionales; los permisos de lectura y escritura en los proyectos de repositorio no serán suficientes.

  3. Instala la GitHub App en tu organización. Instálala para todos los repositorios a los cuales necesita acceso tu proyecto. Para más información, vea "Instalación de GitHub Apps".

  4. Almacena la ID de tu GitHub App como un secreto en tu repositorio u organización. En el flujo de trabajo siguiente, reemplace APP_ID por el nombre del secreto. Puedes encontrar tu ID de app en la página de ajustes de tu app o mediante la API de la misma. Para obtener más información, consulte "Aplicaciones".

  5. Generar una llave privada para tu app. Almacena el contenido del archivo resultante como secreto en tu repositorio u organización. (Almacene todo el contenido del archivo, incluido el contenido de -----BEGIN RSA PRIVATE KEY----- y -----END RSA PRIVATE KEY-----). En el flujo de trabajo siguiente, reemplace APP_PEM por el nombre del secreto. Para más información, vea "Autenticación con GitHub Apps".

  6. En el flujo de trabajo siguiente, reemplace YOUR_ORGANIZATION por el nombre de la organización. Por ejemplo: octo-org. Reemplace YOUR_PROJECT_NUMBER por el número del proyecto. Para encontrar un número de proyecto, revisa su URL. Por ejemplo, https://github.com/orgs/octo-org/projects/5 tiene "5" como número de proyecto.

YAML
# Este flujo de trabajo usa acciones que no GitHub no certifica.
# Estas las proporcionan entidades terceras y las gobiernan
# condiciones de servicio, políticas de privacidad y documentación de soporte
# en línea.

# GitHub recomienda anclar acciones a un SHA de confirmación.
# Para obtener una versión más reciente, debes actualizar el SHA.
# También puedes hacer referencia a una etiqueta o rama, pero la acción puede cambiar sin ninguna advertencia.

name: Add PR to project
on:
  pull_request:
    types:
      - ready_for_review
jobs:
  track_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Generate token
        id: generate_token
        uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
        with:
          app_id: ${{ secrets.APP_ID }}
          private_key: ${{ secrets.APP_PEM }}

      - name: Get project data
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
          ORGANIZATION: YOUR_ORGANIZATION
          PROJECT_NUMBER: YOUR_PROJECT_NUMBER
        run: |
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org){
                projectV2(number: $number) {
                  id
                  fields(first:20) {
                    nodes {
                      ... on ProjectV2Field {
                        id
                        name
                      }
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

          echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
          echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
          echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
          echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV

      - name: Add PR to project
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
          PR_ID: ${{ github.event.pull_request.node_id }}
        run: |
          item_id="$( gh api graphql -f query='
            mutation($project:ID!, $pr:ID!) {
              addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
                item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"

            echo 'ITEM_ID='$item_id >> $GITHUB_ENV

      - name: Get date
        run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV

      - name: Set fields
        env:
          GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
        run: |
          gh api graphql -f query='
            mutation (
              $project: ID!
              $item: ID!
              $status_field: ID!
              $status_value: String!
              $date_field: ID!
              $date_value: Date!
            ) {
              set_status: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $status_field
                value: { 
                  singleSelectOptionId: $status_value
                  }
              }) {
                projectV2Item {
                  id
                  }
              }
              set_date_posted: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $date_field
                value: { 
                  date: $date_value
                }
              }) {
                projectV2Item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent

Flujo de trabajo de ejemplo para autenticarse con un token de acceso personal

  1. Cree un token de acceso personal con los ámbitos project y repo. Para más información, vea "Creación de un token de acceso personal".
  2. Guardar el token de acceso personal como secreto en tu organización o repositorio.
  3. En el flujo de trabajo siguiente, reemplace YOUR_TOKEN por el nombre del secreto. Reemplace YOUR_ORGANIZATION por el nombre de la organización. Por ejemplo, octo-org. Reemplace YOUR_PROJECT_NUMBER por el número del proyecto. Para encontrar un número de proyecto, revisa su URL. Por ejemplo, https://github.com/orgs/octo-org/projects/5 tiene "5" como número de proyecto.
YAML
name: Add PR to project
on:
  pull_request:
    types:
      - ready_for_review
jobs:
  track_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Get project data
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
          ORGANIZATION: YOUR_ORGANIZATION
          PROJECT_NUMBER: YOUR_PROJECT_NUMBER
        run: |
          gh api graphql -f query='
            query($org: String!, $number: Int!) {
              organization(login: $org){
                projectV2(number: $number) {
                  id
                  fields(first:20) {
                    nodes {
                      ... on ProjectV2Field {
                        id
                        name
                      }
                      ... on ProjectV2SingleSelectField {
                        id
                        name
                        options {
                          id
                          name
                        }
                      }
                    }
                  }
                }
              }
            }' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

          echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
          echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
          echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
          echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV

      - name: Add PR to project
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
          PR_ID: ${{ github.event.pull_request.node_id }}
        run: |
          item_id="$( gh api graphql -f query='
            mutation($project:ID!, $pr:ID!) {
              addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
                item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"

            echo 'ITEM_ID='$item_id >> $GITHUB_ENV

      - name: Get date
        run: echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV

      - name: Set fields
        env:
          GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
        run: |
          gh api graphql -f query='
            mutation (
              $project: ID!
              $item: ID!
              $status_field: ID!
              $status_value: String!
              $date_field: ID!
              $date_value: Date!
            ) {
              set_status: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $status_field
                value: { 
                  singleSelectOptionId: $status_value
                  }
              }) {
                projectV2Item {
                  id
                  }
              }
              set_date_posted: updateProjectV2ItemFieldValue(input: {
                projectId: $project
                itemId: $item
                fieldId: $date_field
                value: { 
                  date: $date_value
                }
              }) {
                projectV2Item {
                  id
                }
              }
            }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent

Explicación del flujo de trabajo

La siguiente tabla explica las secciones de los flujos de trabajo de ejemplo y te muestra cómo adaptar los flujos de trabajo para tu propio uso.

on:
  pull_request:
    types:
      - ready_for_review
Este flujo de trabajo se ejecuta cada que una solicitud de cambios en el repositorio se marca como "ready for review".

GitHub App solo:

- name: Generate token
  id: generate_token
  uses: tibdex/github-app-token@36464acb844fc53b9b8b2401da68844f6b05ebb0
  with:
    app_id: ${{ secrets.APP_ID }}
    private_key: ${{ secrets.APP_PEM }}
Usa la acción tibdex/github-app-token para generar un token de acceso de instalación para la aplicación a partir del id. de la aplicación y la clave privada. Más adelante en el flujo de trabajo se accede al token de acceso de instalación como ${{ steps.generate_token.outputs.token }}.

Reemplace APP_ID por el nombre del secreto que contiene el id. de la aplicación.

Reemplace APP_PEM por el nombre del secreto que contiene la clave privada de la aplicación.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER

Token de acceso personal:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  ORGANIZATION: YOUR_ORGANIZATION
  PROJECT_NUMBER: YOUR_PROJECT_NUMBER
Configura las variables para este paso.

Si usa un token de acceso personal, reemplace YOUR_TOKEN por el nombre del secreto que contiene el token de acceso personal.

Reemplace YOUR_ORGANIZATION por el nombre de la organización. Por ejemplo, octo-org.

Reemplace YOUR_PROJECT_NUMBER por el número del proyecto. Para encontrar un número de proyecto, revisa su URL. Por ejemplo, https://github.com/orgs/octo-org/projects/5 tiene "5" como número de proyecto.
gh api graphql -f query='
  query($org: String!, $number: Int!) {
    organization(login: $org){
      projectV2(number: $number) {
        id
        fields(first:20) {
          nodes {
            ... on ProjectV2Field {
              id
              name
            }
            ... on ProjectV2SingleSelectField {
              id
              name
              options {
                id
                name
              }
            }
          }
        }
      }
    }
  }'  -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json

Usa GitHub CLI para consultar a la API el id.del proyecto y devolver el nombre y el id. de los primeros 20 campos del proyecto. fields devuelve una unión y la consulta usa fragmentos insertados (... on) para devolver información acerca de los campos ProjectV2Field y ProjectV2SingleSelectField.

La respuesta se almacena en un archivo denominado project_data.json.

echo 'PROJECT_ID='$(jq '.data.organization.projectV2.id' project_data.json) >> $GITHUB_ENV
echo 'DATE_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Date posted") | .id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo 'TODO_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name=="Todo") |.id' project_data.json) >> $GITHUB_ENV
Analiza la respuesta desde la consulta de la API y almacena las ID relevantes como variables de ambiente. Modifica esto para obtener la ID para los campos u opciones diferentes. Por ejemplo:
  • Para obtener el identificador de un campo denominado Team, agregue echo 'TEAM_FIELD_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") | .id' project_data.json) >> $GITHUB_ENV.
  • Para obtener el id. de una opción denominada Octoteam para el campo de selección única Team, agrega echo 'OCTOTEAM_OPTION_ID='$(jq '.data.organization.projectV2.fields.nodes[] | select(.name== "Team") |.options[] | select(.name=="Octoteam") |.id' project_data.json) >> $GITHUB_ENV.
Nota: En este flujo de trabajo se da por hecho que tiene un proyecto con un único campo de selección denominado "Status" (Estado) que incluye una opción denominada "Todo" (Pendiente) y un campo de fecha denominado "Date posted" (Fecha de publicación). Debes modificar esta sección para empatar con los campos que están presentes en tu tabla.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
  PR_ID: ${{ github.event.pull_request.node_id }}

Token de acceso personal:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
  PR_ID: ${{ github.event.pull_request.node_id }}
Configura las variables para este paso. GITHUB_TOKEN se ha descrito anteriormente. PR_ID es el identificador de la solicitud de incorporación de cambios que ha desencadenado este flujo de trabajo.
item_id="$( gh api graphql -f query='
  mutation($project:ID!, $pr:ID!) {
    addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
      item {
        id
      }
    }
  }' -f project=$PROJECT_ID -f pr=$PR_ID --jq '.data.addProjectV2ItemById.item.id')"
Usa GitHub CLI y la API para agregar la solicitud de incorporación de cambios que ha desencadenado este flujo de trabajo al proyecto. La marca jq analiza la respuesta para obtener el identificador del elemento creado.
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
Almacena la ID del elemento creado como variable de ambiente.
echo "DATE=$(date +"%Y-%m-%d")" >> $GITHUB_ENV
Guarda la fecha actual como una variable de entorno con el formato yyyy-mm-dd.

GitHub App:

env:
  GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}

Token de acceso personal:

env:
  GITHUB_TOKEN: ${{ secrets.YOUR_TOKEN }}
Configura las variables para este paso. GITHUB_TOKEN se ha descrito anteriormente.
gh api graphql -f query='
  mutation (
    $project: ID!
    $item: ID!
    $status_field: ID!
    $status_value: String!
    $date_field: ID!
    $date_value: Date!
  ) {
    set_status: updateProjectV2ItemFieldValue(input: {
      projectId: $project
      itemId: $item
      fieldId: $status_field
      value: { 
        singleSelectOptionId: $status_value
        }
    }) {
      projectV2Item {
        id
        }
    }
    set_date_posted: updateProjectV2ItemFieldValue(input: {
      projectId: $project
      itemId: $item
      fieldId: $date_field
      value: { 
        date: $date_value
      }
    }) {
      projectV2Item {
        id
      }
    }
  }' -f project=$PROJECT_ID -f item=$ITEM_ID -f status_field=$STATUS_FIELD_ID -f status_value=${{ env.TODO_OPTION_ID }} -f date_field=$DATE_FIELD_ID -f date_value=$DATE --silent
Establece el valor del campo Status en Todo. Establece el valor del campo Date posted.