Skip to main content

Usando a CLI do GitHub em um executor

Como usar recursos avançados do GitHub Actions para CI (integração contínua).

Observação: no momento, não há suporte para os executores hospedados no GitHub no GitHub Enterprise Server. Você pode ver mais informações sobre o suporte futuro planejado no GitHub public roadmap.

Visão geral de exemplo

Este artigo usa um fluxo de trabalho de exemplo para demonstrar alguns dos principais recursos de CI do GitHub Actions. Quando esse fluxo de trabalho é disparado, ele executa automaticamente um script que verifica se o site GitHub Docs tem links desfeitos. Quando são encontrados links desfeitos, o fluxo de trabalho usa a CLI do GitHub para criar um problema do GitHub com os detalhes.

O diagrama a seguir mostra uma visão de alto nível das etapas do fluxo de trabalho e como elas são executadas no trabalho:

Diagrama de visão geral das etapas do fluxo de trabalho

Recursos usados neste exemplo

O fluxo de trabalho de exemplo demonstra os seguintes recursos do GitHub Actions:

RecursoImplementação
Executar um fluxo de trabalho em intervalos regulares:schedule

Fluxo de trabalho de exemplo

O fluxo de trabalho a seguir foi criado pela equipe de engenharia de Docs do GitHub. Para revisar a versão mais recente deste arquivo no repositório github/docs, confira check-all-english-links.yml.

Observação: cada linha desse fluxo de trabalho é explicada na próxima seção em "Noções básicas sobre o exemplo".

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@v2
      - name: Setup Node
        uses: actions/setup-node@v2
        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

Compreendendo o exemplo

A tabela a seguir explica como cada um desses recursos é usado ao criar um fluxo de trabalho GitHub Actions.

Código Explicação
YAML
name: Check all English links

O nome do fluxo de trabalho, como aparece na guia "Ações" do repositório do GitHub.

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

Define workflow_dispatch e scheduled como gatilhos para o fluxo de trabalho:

  • O workflow_dispatch permite executar manualmente esse fluxo de trabalho por meio da interface do usuário. Para obter mais informações, confira workflow_dispatch.
  • O evento schedule permite que você use a sintaxe cron para definir um intervalo regular para disparar automaticamente o fluxo de trabalho. Para obter mais informações, confira schedule.
YAML
permissions:
  contents: read
  issues: write

Modifica as permissões padrão concedidas a GITHUB_TOKEN. Isso variará dependendo das necessidades do fluxo de trabalho. Para obter mais informações, confira "Como atribuir permissões a trabalhos".

YAML
jobs:

Agrupa todos os trabalhos executados no arquivo de fluxo de trabalho.

YAML
  check_all_english_links:
    name: Check all links

Define um trabalho com a ID check_all_english_links e o nome Check all links, armazenados dentro da chave jobs.

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

O trabalho check_all_english_links só será executado se o repositório chamar docs-internal e estiver dentro da organização github. Caso contrário, o trabalho será marcado como ignorado.

YAML
runs-on: ubuntu-latest

Configura o trabalho a ser executado em um executor do Ubuntu Linux. Isto significa que o trabalho será executado em uma nova máquina virtual hospedada pelo GitHub. Para ver exemplos de sintaxe que usam outros executores, confira "Sintaxe de fluxo de trabalho do 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

Cria variáveis de ambiente personalizadas e redefine a variável interna GITHUB_TOKEN para usar um segredo personalizado. Essas variáveis serão referenciadas mais tarde no fluxo de trabalho.

YAML
    steps:

Agrupa todas as etapas que serão executadas durante o trabalho check_all_english_links. Cada trabalho no fluxo de trabalho tem a própria seção steps.

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

A palavra-chave uses informa que o trabalho deve recuperar a ação chamada actions/checkout. Esta é uma ação que verifica seu repositório e o faz o download do runner, permitindo que você execute ações contra seu código (como, por exemplo, ferramentas de teste). Você deve usar a ação de checkout sempre que o fluxo de trabalho for executado no código do repositório ou você estiver usando uma ação definida no repositório.

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

Essa etapa usa a ação actions/setup-node para instalar a versão especificada do pacote de software node no executor, o que permite que você acesse o comando npm.

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

A palavra-chave run instrui o trabalho a executar um comando no executor. Nesse caso, os comandos npm ci e npm run build são executados como etapas separadas para instalar e compilar o aplicativo Node.js no repositório.

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

Esse comando run executa um script que é armazenado no repositório em script/check-english-links.js e direciona a saída para um arquivo chamado broken_links.md.

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

Se o script check-english-links.js detectar links desfeitos e retornar um status de saída diferente de zero (falha), use um comando de fluxo de trabalho para definir uma saída que tenha o valor da primeira linha do arquivo broken_links.md (usado na próxima etapa).

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 a ação peter-evans/create-issue-from-file para criar um problema do GitHub. Este exemplo é fixado a uma versão específica da ação, usando o 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 localizar o problema que já foi criado de execuções anteriores. O alias gh list-reports é usado para simplificar o processamento nas próximas etapas. Para obter a URL do problema, a expressão jq processa a saída JSON resultante.

Depois, gh issue comment é usado para adicionar um comentário ao novo problema vinculado ao 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

Se um problema de uma execução anterior estiver aberto e atribuído a alguém, use gh issue comment para adicionar um comentário com um link para o novo problema.

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

Se um problema de uma execução anterior estiver aberto e não estiver atribuído a ninguém:

  • Use gh issue comment para adicionar um comentário com um link para o novo problema.
  • Use gh issue close para fechar o problema antigo.
  • Use gh issue edit para editar o problema antigo a fim de removê-lo de um quadro de projeto do GitHub.

Próximas etapas