Introdução
This guide will introduce you to GitHub Apps and the Checks API, which you'll use to build a continuous integration (CI) server that runs tests.
A CI é uma prática de software que exige o commit do código em um repositório compartilhado. Fazer commits de códigos com frequência detecta erros com mais antecedência e reduz a quantidade de código necessária para depuração quando os desenvolvedores chegam à origem de um erro. As atualizações frequentes de código também facilitam o merge de alterações dos integrantes de uma equipe de desenvolvimento de software. Assim, os desenvolvedores podem se dedicar mais à gravação de códigos e se preocupar menos com erros de depuração ou conflitos de merge. 🙌
Um código de host do servidor de CI que executa testes de CI, como, por exemplo, linters de código (que verificam formatação de estilo), verificações de segurança, cobertura de código e outras verificações de novos commits de códigos em um repositório. OS ervidores de CI podem até criar e implementar código para servidores de treinamento ou produção. Para obter alguns exemplos dos tipos de testes de CI que você pode criar com um aplicativo GitHub, consulte os aplicativos de integração contínua disponíveis no GitHub Marketplace.
Note: Esta guia demonstra o processo de desenvolvimento de aplicativos usando a linguagem de programação Ruby. No entanto, existem muitos flavors of Octokit. Se você preferir o JavaScript, você pode usar Probot e Node.js para desenvolver Aplicativos GitHub.
Visão geral da API de verificação
A API de verificação permite que você configure testes de CI executados automaticamente em cada commit de código em um repositório. A API de verificação relata informações detalhadas sobre cada verificação no GitHub na aba Verificações do pull request. Com a API de Verificações, você pode criar anotações com detalhes adicionais para linhas específicas de código. As anotações são visíveis na aba Verificações. Ao criar uma anotação para um arquivo que faz parte do pull request, as anotações também são exibidas na aba Arquivos alterados.
Um conjunto de verificações é um grupo de execuções de verificação (testes de CI individuais). Tanto o conjunto quanto a execução contêm status visíveis em um pull request no GitHub. Você pode usar os status para determinar quando um commit de código introduz erros. Usar esses status com branches protegidos pode impedir que as pessoas mesclem de pull requests prematuramente. Veja "Sobre branches protegidos" para mais informações.
A API de verificações envia o evento do webhook check_suite
webhook para todos os aplicativos GitHub instalados em um repositório sempre que um novo código for enviado para o repositório. Para receber todas as ações do evento de verificações da API, o aplicativo deverá ter a permissão de checks:write
. O GitHub cria automaticamente eventos check_suite
para novos códigos de commits em um repositório usando o fluxo-padrão, embora Atualizar preferências do repositório para o conjunto de verificações esteja disponível se desejar. Veja como funciona o fluxo-padrão:
- Sempre que alguém fizer push do código para o repositório, o GitHub envia o evento
check_suite
com uma ação denecessária
a todos os aplicativos GitHub instalados no repositório com a permissãochecks:write
. Este evento permite que os aplicativos saibam que o código foi enviado e que o GitHub criou um novo conjunto de verificações automaticamente. - Quando seu aplicativo recebe este evento, ele pode adicionar uma verificação executa para esse conjunto.
- As suas execuções de verificação podem incluir anotações, que são exibidas em linhas específicas de código.
Neste guia, você aprenderá:
- Parte 1: Configurar a estrutura para um servidor de CI usando a API de verificações.
- Configurar um aplicativo GitHub como um servidor que recebe eventos de API de verificações.
- Criar novas execuções de verificação para testes de CI quando um repositório recebe commits recém enviados.
- Reexecutar a verificação quando um usuário solicita que a ação seja executada no GitHub.
- Parte 2: Aproveitar a estrutura do servidor de CI que você criou adicionando um teste de CI de linter.
- Atualize uma verificação executada com um
status
,conclusão
e informações desaída
. - Crie anotações nas linhas de código que o GitHub exibe na aba Verificações e Arquivos alterados de um pull request.
- Corrija automaticamente as recomendações do linter expondo um botão "Corrigir isso" na aba Verificações do pull request.
- Atualize uma verificação executada com um
Para ter uma ideia do que seu servidor de CI da API de verificações fará quando você concluir este início rápido, confira a demonstração abaixo:
Pré-requisitos
Before you get started, you may want to familiarize yourself with GitHub Apps, Webhooks, and the Checks API, if you're not already. Você encontrará mais APIs na documentação da API REST. A API de Verificações também está disponível para uso no GraphQL, mas este início rápido foca no REST. Consulte o GraphQL Conjunto de verificações e os objetos de execução de verificação objetos para obter mais informações.
Você usará a linguagem de programação Ruby, o serviço de entrega de da carga do webhook Smee, a biblioteca do Ruby Octokit.rb para a API REST do GitHub e a estrutura web Sinatra para criar seu aplicativo do servidor de verificações de CI da API.
Não é necessário ser um especialista em nenhuma dessas ferramentas ou conceitos para concluir este projeto. Este guia irá orientá-lo em todas as etapas necessárias. Antes de começar a criar testes de CI com a API de verificações, você deverá fazer o seguinte:
-
Clone o repositório Criando testes de CI a API de verificações.
$ git clone https://github.com/github-developer/creating-ci-tests-with-the-checks-api.git
Dentro do diretório, você encontrará um arquivo
template_server.rb
com o código do template você usará neste início rápido e um arquivoserver.rb
arquivo com o código do projeto concluído. -
Siga as etapas no início rápido "Configurando seu ambiente de desenvolvimento" para configurar e executar o servidor do aplicativo. Observação: Em vez de clonar o repositório de modelo do aplicativo GitHub, use o arquivo
template_server.rb
arquivo no repositório que você clonou no passo anterior neste início rápido.Se você concluiu um início rápido do aplicativo GitHub antes disso, certifique-se de registrar um novo aplicativo GitHub e iniciar um novo canal Smee para usar com este início rápido.
Consulte a seção Resolução de problemas se você tiver problemas ao configurar o modelo do seu aplicativo GitHub.
Parte 1. Criar a interface da API de verificações
Nesta parte, você irá adicionar o código necessário para receber os eventos do webhook verific_suite
irá criar e atualizar as execuções de verificação. Você também aprenderá como criar uma execução de verificação quando solicitou-se a verificação novamente no GitHub. Ao final desta seção, você poderá visualizar a execução de verificação que você criou em um pull request do GitHub.
Sua execução de verificação não realizará nenhuma verificação no código nesta seção. Você adicionará essa funcionalidade na Parte 2: Criando o teste de CI do Octo RuboCop.
Você já deve ter um canal do Smee configurado que encaminha cargas do webhook para o seu servidor local. Seu servidor deve estar em execução e conectado ao aplicativo GitHub que você registrou e instalou em um repositório de teste. Se você não concluiu as etapas em "Configurando seu ambiente de desenvolvimento", você deverá fazer isso antes de continuar.
Vamos começar! Estas são as etapas que você concluirá na Parte 1:
- Atualizar as permissões do aplicativo
- Adicionar manipulação de evento
- Criar uma execução de verificação
- Atualizar a execução de verificação
Etapa 1.1. Atualizar as permissões do aplicativo
Quando você registrou seu aplicativo pela primeira vez, você aceitou as permissões-padrão, o que significa que seu aplicativo não tem acesso à maioria dos recursos. Para este exemplo, seu aplicativo precisará de permissão para ler e gravar verificações.
Para atualizar as permissões do aplicativo:
- Selecione seu aplicativo na página de configurações do aplicativo e clique em Permissões & Webhooks na barra lateral.
- Na seção "Permissões", localize "Verificações" e selecione Leitura & gravação no menu suspenso de Acesso ao lado.
- Na seção "Assinar eventos", selecione Conjunto de verificações e Execução de verificações para assinar esses eventos.
- Clique em Save changes na parte inferior da página.
- Se você instalou o aplicativo na sua conta, verifique seu e-mail e siga o link para aceitar novas permissões. Sempre que você alterar as permissões ou webhooks do seu aplicativo, os usuários que instalaram o aplicativo (incluindo você mesmo) precisarão aceitar as novas permissões antes que as alterações tenham efeito. Você também pode aceitar as novas permissões navegando até sua installations page e clicando em "Configure" ao lado de seu aplicativo. Você verá um banner no topo da página, permitindo que você saiba que o aplicativo está solicitando diferentes permissões. Clique em "Details" e clique em "Accept new permissions."
Ótimo! Seu aplicativo tem permissão para realizar as tarefas que você deseja que ele realize. Agora você pode adicionar o código para gerenciar os eventos.
Etapa 1.2. Adicionar manipulação de evento
Agora que seu aplicativo assinou os eventos Conjunto de verificações e na Execução de verificações, ele irá começar a receber os webhooks check_suite
e check_run
. O GitHub envia cargas do webhook como solicitações de POST
. Porque você encaminhou as cargas do webhook do smee para http://localhost/event_handler:3000
, seu servidor receberá as cargas de solicitação POST
no encaminhamento post '/event_handler'
.
Um encaminhamento vazio post '/event_handler'
já está incluído no arquivo template_server.rb
, que você baixou na seção pré-requisitos. O encaminhamento vazio tem a seguinte forma:
post '/event_handler' do
# # # # # # # # # # # #
# ADD YOUR CODE HERE #
# # # # # # # # # # # #
200 # success status
end
Use este encaminhamento para gerenciar o evento check_suite
adicionando o código a seguir:
# Obtenha o tipo de evento a partir do cabeçalho HTTP_X_GITHUB_EVENT
case request.env['HTTP_X_GITHUB_EVENT']
quando 'check_suite'
# Um novo check_suite foi criado. Crie uma nova execução de verificação com status enfileirado
if @payload['action'] == 'requested' || @payload['action'] == 'rerequested'
create_check_run
end
end
Cada evento que o GitHub envia inclui um cabeçalho de solicitação denominado HTTP_X_GITHUB_EVENT
, que indica o tipo de evento na solicitação de POST
. No momento, você está interessado apenas em eventos do tipo check_suite
, emitidos quando um novo conjunto de verificações é criado. Cada evento tem um campo ação
adicional que indica o tipo de ação que acionou os eventos. Para check_suite
, o campo ação
pode ser solicitado
, ressolicitado
ou concluído
.
A ação solicitada
solicita uma execução de verificação cada vez que o código é enviado para o repositório, ao passo que a ação ressolicitada
solicita que você execute novamente uma verificação para o código que já existe no repositório. Como as ações solicitadas
e ressolicitadas
exigem a criação de uma execução de verificação, você chamará um auxiliar denominado create_check_run
. Vamos escrever esse método agora.
Etapa 1.3. Criar uma execução de verificação
Você irá adicionar este novo método como um Auxiliar do Sinatra, caso deseje que outros encaminhamentos o usem também. Em auxiliares do
, adicione este método create_check_run
:
# Create a new check run with the status queued
def create_check_run
# # At the time of writing, Octokit does not support the Checks API yet, but
# it does provide generic HTTP methods you can use:
# /rest/reference/checks#create-a-check-run
check_run = @installation_client.post(
"repos/#{@payload['repository']['full_name']}/check-runs",
{
# This header allows for beta access to Checks API
accept: 'application/vnd.github.antiope-preview+json',
# The name of your check run.
nome: 'Octo RuboCop',
# A estrutura da carga difere dependendo da ocorrência de um evento de execução de verificação ou de conjunto de verificações.
head_sha: @payload['check_run'].nil? ? @payload['check_suite']['head_sha'] : @payload['check_run']['head_sha']
}
)
end
Este código chama o ponto de extremidade "Criar uma execução de verificação" que usa o método genérico HTTP POST
. Este método tem dois parâmetros: a URL do ponto final e os parâmetros de entrada do método.
Para criar uma execução de verificação, são necessários apenas dois parâmetros de entrada: nome
e head_sha
. Vamos usar o Rubocop para implementar o teste CI mais adiante início rápido. Por esse motivo, o nome "Octo Rubocop" é usado aqui, mas você pode escolher qualquer nome que desejar para a execução da verificação.
Você só está fornecendo os parâmetros necessários agora para que a funcionalidade básica funcione, mas você irá atualizar a verificação de execução posteriormente enquanto coleta mais informações sobre a verificação de execução. Por padrão, o GitHub define o status
como enfileirado
.
O GitHub cria uma execução de verificação para um commit SHA específico. É por isso que head_sha
é um parâmetro necessário. Você pode encontrar commit SHA na carga do webhook. Embora você esteja apenas criando uma execução de verificação para o evento check_suite
neste momento, é bom saber que o head_sha
está incluído em ambos os objetos check_suite
e check_run
nas cargas do evento.
No código acima, você está usando o operador ternário, que funciona como uma instrução if/else
para verificar se a carga contém um objeto check_run
. Em caso afirmativo, você lê o head_sha
a partir do objeto check_run
. Caso contrário você o lê a partir do objeto check_suite
.
Para testar esse código, reinicie o servidor a partir do seu terminal:
$ ruby template_server.rb
Nota: Você precisará reiniciar o servidor Sinatra para testar as alterações. Digite Ctrl-C
para parar o servidor, e então execute ruby template_server.rb
novamente. Se você não quiser fazer isso toda vez que mudar o seu código de aplicativo, você pode olhar para reloading.
Agora abra um pull request no repositório em que você instalou seu aplicativo. Seu aplicativo deve responder, criando uma verificação executada em seu pull request. Clique na aba Verificações e você deve ver algo parecido com isso:
Se você vir outros aplicativos na aba Verificações, isso significa que você tem outros aplicativos instalados no seu repositório que têm acesso de leitura & gravação para verificações e que estão inscritos em eventos Conjunto de verificações e Execução de verificações.
Ótimo! Você disse ao GitHub para criar uma execução de verificação. Você pode ver que o status da execução de verificação está definido como enfileirado
ao lado de um ícone amarelo. Em seguida, você irá aguardar que o GitHub crie a execução de verificação e atualize seu status.
Etapa 1.4. Atualizar a execução de verificação
Quando o seu método create_check_run
é executado, ele pede ao GitHub para criar uma nova execução de verificação. When GitHub finishes creating the check run, you'll receive the check_run
webhook event with the created
action. Esse evento é o sinal para começar a executar a verificação.
Você vai atualizar o manipulador do evento para procurar a ação criada
. Enquanto você está atualizando o manipulador de eventos, você pode adicionar uma condição para a ação ressolicitada
. Quando alguém executa novamente um único teste no GitHub clicando no botão "Reexecutar", o GitHub envia o evento da execução de verificação ressolicitado
para o seu aplicativo. Quando a execução de uma verificação é ressolicitada
, você irá iniciar todo o processo e criar uma nova execução de verificação.
Para incluir uma condição para o evento check_run
no encaminhamento post '/event_handler'
, adicione o seguinte código em case request.env['HTTP_X_GITHUB_EVENT']
:
when 'check_run'
# Check that the event is being sent to this app
if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
case @payload['action']
when 'created'
initiate_check_run
when 'rerequested'
create_check_run
end
end
O GitHub envia todos os eventos para as execuções de verificação criadas
para todos os aplicativos instalados em um repositório que tenha as permissões de verificações necessárias. Isso significa que seu aplicativo receberá uma verificação que será executada por outros aplicativos. Uma execução de verificação criada
é um pouco diferente de um conjunto de verificações solicitado
ou ressolicitado
, que o GitHub envia apenas para aplicativos que estão sendo ressolicitados para executar uma verificação. O código acima procura o ID do aplicativo da execução de verificação. Isto filtra todas as execuções de verificação de outros aplicativos no repositório.
Em seguida, você irá escrever o método initiate_check_run
, que é onde você vai atualizar o status da sua execução de verificação e preparar-se para iniciar o seu teste de CI.
Nesta seção, você não vai iniciar o teste de CI ainda, mas você verá como atualizar o status da verificação de execução de enfileirado
até pendente
e, em seguida, de pendente
até concluído
para ver o fluxo geral de uma execução de verificação. Na "Parte 2: Criando o teste de CI do Octo RuboCop", você irá adicionar o código que realmente realiza o teste de CI.
Vamos criar o método initiate_check_run
e atualizar o status da execução de verificação. Adicione o seguinte código à seção auxiliar:
# Start the CI process
def initiate_check_run
# Once the check run is created, you'll update the status of the check run
# to 'in_progress' and run the CI process. When the CI finishes, you'll
# update the check run status to 'completed' and add the CI results.
# Octokit doesn't yet support the Checks API, but it does provide generic
# HTTP methods you can use:
# /rest/reference/checks#update-a-check-run
updated_check_run = @installation_client.patch(
"repos/#{@payload['repository']['full_name']}/check-runs/#{@payload['check_run']['id']}",
{
accept: 'application/vnd.github.antiope-preview+json', # This header is necessary for beta access to Checks API
name: 'Octo RuboCop',
status: 'in_progress',
started_at: Time.now.utc.iso8601
}
)
# ***** RUN A CI TEST *****
# Mark the check run as complete!
updated_check_run = @installation_client.patch(
"repos/#{@payload['repository']['full_name']}/check-runs/#{@payload['check_run']['id']}",
{
# This header is necessary for beta access to Checks API
accept: 'application/vnd.github.antiope-preview+json',
name: 'Octo RuboCop',
status: 'completed',
conclusion: 'success',
completed_at: Time.now.utc.iso8601
}
)
end
O código acima chama o ponto de extremidade da API "Atualizar uma execução de verificação" usando o método genérico patch
HTTP para atualizar a execução da verificação que você já criou.
Veja o que este código está fazendo. Primeiro, ele atualiza o status de verificação de execução para in_progress
e define o tempo do started_at
para o tempo atual. Na Parte 2 deste início rápido, você irá adicionar um código que inicia um teste de CI real em ***** EXECUTAR UM TEST DE CI *****
. Por enquanto, você sairá da seção como um espaço reservado, para que o código que o segue apenas simule que o processo de CI seja bem-sucedido e todos os testes sejam aprovados. Finalmente, o código atualiza o status da execução de verificação novamente para concluído
.
Na documentação "Atualizar uma execução de verificação", você observará que, ao fornecer um status de concluído
, são necessários os parâmetros conclusão
e completed_at
. A conclusão `resume o resultado de uma verificação de resultado e pode ser
sucesso,
falha,
neutro,
cancelado,
timed_outou
action_required. Você irá definir a conclusão como
sucesso, o tempo
completed_atcomo a hora atual e o status como
concluído`.
Você também pode fornecer mais informações sobre o que a sua verificação está fazendo, mas você poderá fazer isso na próxima seção. Vamos testar este código de novo executando template_server.rb
novamente:
$ ruby template_server.rb
Vá para seu pull request aberto e clique na aba Verificações. Clique no botão "Executar tudo novamente" no canto superior esquerdo. Você deverá ver a execução da verificação mover de pendente
para in_progress
e terminar com sucesso
:
Parte 2. Criar o teste de CI do Octo RuboCop
RuboCop é um linter do código do Ruby e um formatador. Ele verifica o código do Ruby para garantir que esteja de acordo com o "Guia de estilo do Ruby". O RuboCop tem três funções principais:
- Linting para verificação do estilo do código
- Formatação do código
- Substitui os recursos de linting nativos do Rubi usando
ruby -w
Agora que a interface foi criada para receber eventos da API de verificações e criar execuções de verificação, você pode criar uma execução de verificação que implemente um teste de CI.
Seu aplicativo irá executar o RuboCop no servidor de CI e irá criar uma execuções de verificação (neste caso, testes de CI), que relatarão os resultados que o RuboCop relata para o GitHub.
A API de verificações permite que você relate informações valiosas sobre cada execução de verificação, incluindo status, imagens, resumos, anotações e ações solicitadas.
As anotações são informações sobre linhas específicas de código em um repositório. Uma anotação permite que você identifique e visualize as partes exatas do código para as quais você gostaria de mostrar informações adicionais. Essas informações podem ser qualquer coisa: por exemplo, um comentário, um erro ou um aviso. Este início rápido usa anotações para visualizar erros no RuboCop.
Para aproveitar as ações solicitadas, os desenvolvedores de aplicativos podem criar botões na aba Verificações dos pull requests. Quando alguém clica em um desses botões, o clique envia um evento requested_action
check_run
para o aplicativo GitHub. A ação tomada pelo aplicativo é completamente configurável pelo desenvolvedor do aplicativo. Este início rápido irá orientá-lo no processo de adição de um botão que permite aos usuários solicitar que o RuboCop corrija os erros que encontrar. O RuboCop é compatível com a correção automática de erros usando uma opção de linha de comando, e você irá configurar a requested_action
para aproveitar esta opção.
Vamos começar! Estas são as etapas que você concluirá nesta seção:
- Adicionar um arquivo do Ruby
- Clonar um repositório
- Executar o RuboCop
- Coletar erros do RuboCop
- Atualizar a execução de verificação com resultados dos testes de CI
- Corrigir erros do RuboCop automaticamente
- Dicas de segurança
Etapa 2.1. Adicionar um arquivo do Ruby
Você pode passar arquivos específicos ou diretórios inteiros para o RuboCop verificar. Nesse início rápido, você irá executar o RuboCop em um diretório inteiro. Como RuboCop verifica apenas códigos Ruby, será necessário pelo menos um arquivo Ruby no seu repositório que contém erros. O arquivo de exemplo fornecido abaixo contém alguns erros. Adicione este exemplo de arquivo Ruby ao repositório onde seu aplicativo está instalado (certifique-se de nomear o arquivo com uma extensão .rb
, como em myfile.rb
):
# The Octocat class tells you about different breeds of Octocat
class Octocat
def initialize(name, *breeds)
# Instance variables
@name = name
@breeds = breeds
end
def display
breed = @breeds.join("-")
puts "I am of #{breed} breed, and my name is #{@name}."
end
end
m = Octocat.new("Mona", "cat", "octopus")
m.display
Etapa 2.2. Clonar um repositório
O RuboCop está disponível como um utilitário da linha de comando. Isso significa que o seu aplicativo GitHub deverá clonar uma cópia local do repositório no servidor da CI para que RuboCop possa analisar os arquivos. Para executar operações do Git no seu aplicativo Ruby, você pode usar o gem de ruby-git.
O Gemfile
no repositório building-a-checks-api-ci-server
já inclui a gem de ruby-git, e você o instalou quando executou a instalação em conjunto
nas etapas requisitadas. Para usar a gem, adicione este código à parte superior do seu arquivo template_server.rb
:
requer "git"
Seu aplicativo deve permissão de leitura para "Conteúdo do repositório" para clonar um repositório. Mais adiante neste início rápido, você deverá fazer push de conteúdo para o GitHub, o que exige permissão de gravação. Defina a permissão de "Conteúdo do repositório" do seu aplicativo como leitura & gravação agora, para que você não precise atualizar novamente mais tarde. Para atualizar as permissões do aplicativo:
- Selecione seu aplicativo na página de configurações do aplicativo e clique em Permissões & Webhooks na barra lateral.
- Na seção "Permissões", encontre "Conteúdo do repositório" e selecione Leitura & gravação no menu suspenso "Acesso" ao lado.
- Clique em Save changes na parte inferior da página.
- Se você instalou o aplicativo na sua conta, verifique seu e-mail e siga o link para aceitar novas permissões. Sempre que você alterar as permissões ou webhooks do seu aplicativo, os usuários que instalaram o aplicativo (incluindo você mesmo) precisarão aceitar as novas permissões antes que as alterações tenham efeito. Você também pode aceitar as novas permissões navegando até sua installations page e clicando em "Configure" ao lado de seu aplicativo. Você verá um banner no topo da página, permitindo que você saiba que o aplicativo está solicitando diferentes permissões. Clique em "Details" e clique em "Accept new permissions."
Para clonar um repositório usando as permissões do seu aplicativo GitHub você pode usar o token de instalação do aplicativo (x-access-token:<token>
) mostrado no exemplo abaixo:
git clone https://x-access-token:@github.com//.git
O código acima clone um repositório por HTTP. Isto exige o nome completo do repositório, que inclui o proprietário do repositório (usuário ou organização) e o nome do repositório. Por exemplo, o nome completo do repositório octocat Hello-World é octocat/hello-world
.
Depois que seu aplicativo clonar o repositório, ele deverá resgatar as alterações mais recentes do código fazer checkout do Git ref específico. O código para fazer tudo isto encaixa-se perfeitamente no seu próprio método. Para realizar essas operações, o método precisa do nome e nome completo do repositório e que o ref faça checkout. O ref pode ser um commit SHA, branch ou tag. Adicione o método a seguir à seção do método auxiliar no template_server.rb
:
# Clones the repository to the current working directory, updates the
# contents using Git pull, and checks out the ref.
#
# full_repo_name - The owner and repo. Ex: octocat/hello-world
# repository - The repository name
# ref - The branch, commit SHA, or tag to check out
def clone_repository(full_repo_name, repository, ref)
@git = Git.clone("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", repository)
pwd = Dir.getwd()
Dir.chdir(repository)
@git.pull
@git.checkout(ref)
Dir.chdir(pwd)
end
O código acima usa a gem ruby-git
para clonar o repositório usando o token de instalação do aplicativo. Esse código clona o código no mesmo diretório como o template_server.rb
. Para executar comandos Git no repositório, o código deve alterar para o diretório do repositório. Antes de mudar os diretórios, o código armazena o diretório de trabalho atual em uma variável (pwd
) para lembrar para onde retornar antes de sair do método clone_repository
.
No diretório do repositório, este código busca e mescla as últimas alterações (@git.pull
), faz o checkout do ref (@git. heckout(ref)
) e, em seguida, muda o diretório de volta para o diretório de trabalho original (pwd
).
Agora você tem um método que clona um repositório e faz o checkout de um ref. Em seguida, você deve adicionar código para obter os parâmetros de entrada necessários e chamar o novo método clone_repository
. Adicione o código a seguir no comentário ***** RUN A CI TEST *****
no seu método auxiliar initiate_check_run
:
# ***** RUN A CI TEST *****
full_repo_name = @payload['repository']['full_name']
repository = @payload['repository']['name']
head_sha = @payload['check_run']['head_sha']
clone_repository(full_repo_name, repository, head_sha)
O código acima obtém o nome completo do repositório e o SHA principal do commit da carga do webhook check_run
.
Etapa 2.3. Executar o RuboCop
Ótimo! Você está clonando o repositório e criando execuções de verificação usando seu servidor de CI. Agora você irá entrar nas informações principais do RuboCop linter e das anotações da API de verificação.
O código a seguir executa RuboCop e salva os erros do código de estilo no formato JSON. Adicione este código abaixo da chamada para clone_repository
que você adicionou na etapa anterior e acima do código que atualiza a execução de verificação para concluir.
# Run RuboCop on all files in the repository
@report = `rubocop '#{repository}' --format json`
logger.debug @report
`rm -rf #{repository}`
@output = JSON.parse @report
O código acima executa o RuboCop em todos os arquivos no diretório do repositório. A opção --format json
é uma maneira útil de salvar uma cópia dos resultados de linting, em um formato analisável por máquina. Consulte a documentação do RuboCop para obter informações e um exemplo do formato JSON.
Como esse código armazena os resultados do RuboCop em uma variável @report
, ele pode remover o checkout do repositório com segurança. Este código também analisa o JSON para que possa acessar facilmente as chaves e valores no seu aplicativo GitHub usando a variável @output
.
Observação: Não é possível desfazer o comando usado para remover o repositório (rm -rf
). Consulte Etapa 2.7. Dicas de segurança para aprender como verificar webhooks sobre comandos maliciosos injetados que podem ser usados para remover um diretório diferente do que era esperado pelo seu aplicativo. Por exemplo, se um ator ruim enviasse um webhook com o nome do repositório ./
, seu aplicativo removeria o diretório-raiz. 😱 Se, por algum motivo, você não está usando o método verify_webhook_signature
(incluído no template_server.rb
) para validar o remetente do webhook, certifique-se de que o nome do repositório seja válido.
Você pode testar se este código funciona e ver os erros relatados pelo RuboCop na saída de depuração do seu servidor. Reinicie o servidor template_server.rb
e crie um novo pull request no repositório em que você está testando seu aplicativo:
$ ruby template_server.rb
Você deve ver os erros de linting na saída de depuração, embora não sejam impressos com a formatação. Você pode usar uma ferramenta como oformatador JSON para formatar sua saída do JSON como esta saída de erro de do linting formatado:
{
"metadata": {
"rubocop_version": "0.60.0",
"ruby_engine": "ruby",
"ruby_version": "2.3.7",
"ruby_patchlevel": "456",
"ruby_platform": "universal.x86_64-darwin18"
},
"files": [
{
"path": "Octocat-breeds/octocat.rb",
"offenses": [
{
"severity": "convention",
"message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
"cop_name": "Style/StringLiterals",
"corrected": false,
"location": {
"start_line": 17,
"start_column": 17,
"last_line": 17,
"last_column": 22,
"length": 6,
"line": 17,
"column": 17
}
},
{
"severity": "convention",
"message": "Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.",
"cop_name": "Style/StringLiterals",
"corrected": false,
"location": {
"start_line": 17,
"start_column": 25,
"last_line": 17,
"last_column": 29,
"length": 5,
"line": 17,
"column": 25
}
}
]
}
],
"summary": {
"offense_count": 2,
"target_file_count": 1,
"inspected_file_count": 1
}
}
Etapa 2.4. Coletar erros do RuboCop
A variável @output
contém os resultados do JSON analisados do relatório do RuboCop. Conforme mostrado acima, os resultados contêm uma seção resumo
que seu código pode usar para determinar rapidamente se existem erros. O código a seguir definirá a conclusão de execução de verificação para o sucesso
quando não houver erros relatados. O RuboCop relata erros para cada arquivo no array dos arquivos
. Portanto, se houver erros, você deverá extrair alguns dados do objeto arquivo.
A API de verificação permite que você crie anotações para linhas específicas do código. Ao criar ou atualizar uma execução de verificação, você pode adicionar anotações. Neste início rápido, você está atualizando a execução de verificações com anotações.
A API de verificação limita o número de anotações a um máximo de 50 por solicitação de API. Para criar mais de 50 anotações, você deverá fazer várias solicitações para o ponto de extremidade Atualizar uma execução de verificação. Por exemplo, para criar 105 anotações você deve chamar o ponto de extremidade Atualizar uma execução de verificação três vezes. Cada uma das duas primeiras solicitações teria 50 anotações e a terceira solicitação incluiria as cinco anotações restantes. Cada vez que você atualizar a execução de verificação, as anotações são anexadas à lista de anotações que já existem para a execução de verificação.
Uma execução de verificação espera anotações como um array de objetos. Cada objeto de anotação deve incluir o caminho
, start_line
,, end_line
, annotation_level
e mensagem
. O RuboCop também fornece start_column
e end_column
. Portanto, você pode incluir esses parâmetros opcionais na anotação. As anotações são compatíveis apenas com start_column
e end_column
na mesma linha. Para obter mais informações, consulte a documentação de referência do objeto anotações
.
Você irá extrair as informações necessárias do RuboCop para criar cada anotação. Acrescente o seguinte código ao código que você adicionou na seção anterior:
annotations = []
# You can create a maximum of 50 annotations per request to the Checks
# API. To add more than 50 annotations, use the "Update a check run" API
# endpoint. Este código de exemplo limita o número de anotações a 50.
# See /rest/reference/checks#update-a-check-run
# for details.
max_annotations = 50
# RuboCop reports the number of errors found in "offense_count"
if @output['summary']['offense_count'] == 0
conclusion = 'success'
else
conclusion = 'neutral'
@output['files'].each do |file|
# Only parse offenses for files in this app's repository
file_path = file['path'].gsub(/#{repository}\//,'')
annotation_level = 'notice'
# Parse each offense to get details and location
file['offenses'].each do |offense|
# Limit the number of annotations to 50
next if max_annotations == 0
max_annotations -= 1
start_line = offense['location']['start_line']
end_line = offense['location']['last_line']
start_column = offense['location']['start_column']
end_column = offense['location']['last_column']
message = offense['message']
# Create a new annotation for each error
annotation = {
path: file_path,
start_line: start_line,
end_line: end_line,
start_column: start_column,
end_column: end_column,
annotation_level: annotation_level,
message: message
}
# Annotations only support start and end columns on the same line
if start_line == end_line
annotation.merge({start_column: start_column, end_column: end_column})
end
annotations.push(annotation)
end
end
end
Este código limita o número total de anotações a 50. Mas você pode modificar este código para atualizar a verificação de execução para cada lote de 50 anotações. O código acima inclui a variável max_annotations
que define o limite para 50, que é usado no loop que itera por meio das ofensas.
Quando o offense_count
é zero, o teste de CI é um sucesso
. Se houver erros, este código definirá a conclusão como neutro
para evitar estritamente a imposição de erros dos linters do código. Mas você pode alterar a conclusão para falha
se desejar garantir que o conjunto de verificações falhe quando houver erros de linting.
Quando os erros são relatados, o código acima afirma por meio da array de arquivos
no relatório do RuboCop. Para cada arquivo, ele extrai o caminho do arquivo e define o nível de anotação como aviso
. Você pode ir além e definir os níveis específicos de aviso para cada tipo de RuboCop Cop, mas simplificar as coisas neste início rápido, todos os erros são definidos para um nível de aviso
.
Este código também é afirmado por meio de cada erro no array de ofensas
e coleta o local da mensagem de erro e de ofensa. Após extrair as informações necessárias, o código cria uma anotação para cada erro e a armazena no array de anotações
. Uma vez que as anotações são compatíveis apenas com colunas iniciais e finais na mesma linha, start_column
e end_column
só são adicionados ao objeto anotação
se os valores da linha inicial e final forem iguais.
Esse código ainda não cria uma anotação para a execução de verificação. Você irá adicionar esse código na próxima seção.
Etapa 2.5. Atualizar a execução de verificação com resultados dos testes de CI
Cada execução de verificação no GitHub contém um objeto de saída
que inclui um título
, resumo
, texto
, anotações
e imagens
. O resumo
e o título
são os únicos parâmetros necessários para a saída
, mas eles não oferecem muitas informações. Portanto, este início rápido adiciona também texto
e anotações
. Aqui, o código não adiciona uma imagem, mas sinta-se à vontade para adicionar uma, se desejar!
Para o resumo
, este exemplo usa a informação de resumo do RuboCop e adiciona algumas novas linhas (\n
) para formatar a saída. É possível personalizar o que você adiciona ao parâmetro texto
, mas este exemplo define o parâmetro texto
para a versão do RuboCop. Para definir o resumo
e o texto
, adicione este código ao código que você adicionou na seção anterior:
# Updated check run summary and text parameters
summary = "Octo RuboCop summary\n-Offense count: #{@output['summary']['offense_count']}\n-File count: #{@output['summary']['target_file_count']}\n-Target file count: #{@output['summary']['inspected_file_count']}"
text = "Octo RuboCop version: #{@output['metadata']['rubocop_version']}"
Agora você tem todas as informações de que precisa para atualizar sua execução de verificação. Na primeira metade deste início rápido, você adicionou este código para definir o status da execução de verificação de sucesso
:
# Mark the check run as complete!
updated_check_run = @installation_client.patch(
"repos/#{@payload['repository']['full_name']}/check-runs/#{@payload['check_run']['id']}",
{
accept: 'application/vnd.github.antiope-preview+json', # This header is necessary for beta access to Checks API
name: 'Octo RuboCop',
status: 'completed',
conclusion: 'success',
completed_at: Time.now.utc.iso8601
}
)
Você deverá atualizar esse código para usar a variável de conclusão
definida com base nos resultados do RuboCop (para sucesso
ou neutro
). Você pode atualizar o código com o seguinte:
# Mark the check run as complete! E, se houver avisos, compartilhe-os.
updated_check_run = @installation_client.patch(
"repos/#{@payload['repository']['full_name']}/check-runs/#{@payload['check_run']['id']}",
{
accept: 'application/vnd.github.antiope-preview+json',
name: 'Octo RuboCop',
status: 'completed',
conclusion: conclusion,
completed_at: Time.now.utc.iso8601,
output: {
title: 'Octo RuboCop',
summary: summary,
text: text,
annotations: annotations
},
actions: [{
label: 'Fix this',
description: 'Automatically fix all linter notices.',
identifier: 'fix_rubocop_notices'
}]
}
)
Agora que você está definindo uma conclusão com base no status do teste CI e que você adicionou a saída dos resultados do RuboCop, você criou um teste de CI! Parabéns. 🙌
O código acima também adiciona um recurso ao seu servidor de CI denominado ações solicitadas por meio do objeto ações
. As ações solicitadas adicionam um botão à aba Verificações no GitHub que permite que alguém solicite execução de verificação para tomar medidas adicionais. A ação adicional é completamente configurável pelo seu aplicativo. Por exemplo, uma vez que o RuboCop tem um recurso para corrigir automaticamente os erros que encontra no código Ruby, seu servidor de CI pode usar um botão de ações solicitadas para permitir que as pessoas solicitem correções automáticas de erros. Quando alguém clica no botão, o aplicativo recebe o evento de check_run
com uma ação requested_action
. Cada ação solicitada tem um identificador
que o aplicativo usa para determinar em qual botão foi clicado.
O código acima ainda não exige que o RuboCop corrija erros automaticamente. Você irá adicionar isso na próxima seção. Mas, primeiro, dê uma olhada no teste de CI que você acabou de criar ao iniciar o servidor template_server.rb
novamente e ao criar um novo pull request:
$ ruby template_server.rb
As anotações serão exibidas na aba Verificações.
Observe o botão "Corrija isso" que você criou ao adicionar uma ação solicitada.
Se as anotações estiverem relacionadas a um arquivo já incluído no PR, as anotações também serão exibidas na aba Arquivos alterados.
Etapa 2.6. Corrigir erros do RuboCop automaticamente
Se você chegou até aqui, parabéns! 👏 Você já criou um teste de CI. Nesta seção, você irá adicionar mais um recurso que usa RuboCop para corrigir automaticamente os erros que encontra. Você já adicionou o botão "Corrija isso" na seção anterior. Agora você irá adicionar o código para lidar com o evento de execução de verificação requested_action
acionado quando alguém clica no botão "Corrija isso".
A ferramenta do RuboCop oferece a opção de linha de comando --auto-correct
para corrigir automaticamente os erros que encontra. Ao usar o recurso --auto-correct
, as atualizações são aplicadas aos arquivos locais do servidor. Você deverá fazer push das alterações no GitHub depois que o RuboCop fizer sua mágica.
Para fazer push para um repositório, seu aplicativo deve ter permissões de "conteúdo do repositório". Você redefiniu essa permissão na Etapa 2.2. Clonar o repositório para Leitura & gravação. Agora, você está pronto.
Para enviar arquivos do commit, o Git deve saber qual o nome de usuário e e-mail devem ser associados ao commit. Adicione mais duas variáveis de ambiente ao seu arquivo .env
para armazenar as configurações do nome (GITHUB_APP_USER_NAME
) e do e-mail (GITHUB_APP_USER_EMAIL
). Seu nome pode ser o nome do seu aplicativo e o e-mail pode ser qualquer e-mail que desejar para este exemplo. Por exemplo:
GITHUB_APP_USER_NAME=Octoapp
GITHUB_APP_USER_EMAIL=octoapp@octo-org.com
Uma vez atualizado o seu arquivo .env
com o nome e o e-mail do autor e do committer, você estará pronto para adicionar código para ler as variáveis de ambiente e definir a configuração do Git. Você irá adicionar esse código em breve.
Quando alguém clica no botão "Corrija isso", seu aplicativo recebe o webhook da execução de verificação com o tipo de ação requested_action
.
Na Etapa 1.4. Ao atualizar uma verificação, você atualizou o seu event_handler
para lidar com a procura de ações no evento check_run
. Você já tem uma afirmação de caso para lidar com os tipos de ação criado
e ressolicitado
:
when 'check_run'
# Check that the event is being sent to this app
if @payload['check_run']['app']['id'].to_s === APP_IDENTIFIER
case @payload['action']
when 'created'
initiate_check_run
when 'rerequested'
create_check_run
end
end
Adicione outra afirmação de quando
após o caso ressolicitado
para lidar com o evento rerequested_action
:
quando 'requested_action'
take_requested_action
Este código chama um novo método que irá lidar com todos os eventos requested_action
para seu aplicativo. Adicione o seguinte método à seção de métodos auxiliares do seu código:
# Handles the check run `requested_action` event
# See /webhooks/event-payloads/#check_run
def take_requested_action
full_repo_name = @payload['repository']['full_name']
repository = @payload['repository']['name']
head_branch = @payload['check_run']['check_suite']['head_branch']
if (@payload['requested_action']['identifier'] == 'fix_rubocop_notices')
clone_repository(full_repo_name, repository, head_branch)
# Sets your commit username and email address
@git.config('user.name', ENV['GITHUB_APP_USER_NAME'])
@git.config('user.email', ENV['GITHUB_APP_USER_EMAIL'])
# Automatically correct RuboCop style errors
@report = `rubocop '#{repository}/*' --format json --auto-correct`
pwd = Dir.getwd()
Dir.chdir(repository)
begin
@git.commit_all('Automatically fix Octo RuboCop notices.')
@git.push("https://x-access-token:#{@installation_token.to_s}@github.com/#{full_repo_name}.git", head_branch)
rescue
# Nothing to commit!
puts 'Nothing to commit'
end
Dir.chdir(pwd)
`rm -rf '#{repository}'`
end
end
O código acima clona um repositório como o código que você adicionou na Etapa 2.2. Clonar o repositório. Uma afirmação se
verifica se o identificador da ação solicitada corresponde ao identificador do botão do RuboCop (fix_rubocop_notices
). Quando correspondem, o código clona o repositório, define o nome de usuário e e-mail do Git e executa o RuboCop com a opção --auto-correct
. A opção --auto-correct
aplica automaticamente as alterações para os arquivos locais do servidor de CI.
Os arquivos são alterados localmente, mas você ainda deverá enviá-los para o GitHub. Você usará a gem útil ruby-git
novamente para comprometer todos os arquivos. O Git tem um único comando que monta todos os arquivos modificados ou excluídos e compromete-os: git commit -a
. Para fazer a mesma coisa utilizando o ruby-git
, o código acima usa o método commit_all
. Em seguida, o código faz push dos arquivos comprometidos para o GitHub usando o token de instalação, que usa o mesmo método de autenticação do comando clonar
do Git. Por fim, ele remove o diretório do repositório para garantir que o diretório de trabalho seja preparado para o próximo evento.
Pronto! O código que você escreveu agora conclui o servidor de CI da API de verificação. 💪 Reinicie seu servidor template_server.rb
e crie um novo pull request:
$ ruby template_server.rb
Nota: Você precisará reiniciar o servidor Sinatra para testar as alterações. Digite Ctrl-C
para parar o servidor, e então execute ruby template_server.rb
novamente. Se você não quiser fazer isso toda vez que mudar o seu código de aplicativo, você pode olhar para reloading.
Desta vez, clique no botão "Corrija isso" para corrigir automaticamente os erros encontrados no RuboCop na aba Verificações.
Na aba Commits, você verá um novo commit pelo nome de usuário que você definiu na sua configuração do Git. Talvez seja necessário atualizar seu navegador para ver a atualização.
Como um novo commit foi enviado para o repositório, você verá um novo conjunto de verificações para Octo RuboCop na aba Verificações. Mas desta vez não haverá erros, porque o RuboCop resolveu todos eles. 🎉
Você pode encontrar o código concluído para o aplicativo que você acabou de criar no arquivo server.rb
no repositório Criar testes de CI com a API de verificações.
Etapa 2.7. Dicas de segurança
O modelo de código do aplicativo GitHub já possui um método para verificar as cargas do webhook de entrada para garantir que sejam de uma fonte confiável. Se você não estiver validando as cargas do webhook, você deverá garantir que, quando nomes do repositório estiverem incluídos na carga do webhook, este não conterá comandos arbitrários que possam ser usados maliciosamente. O código abaixo valida que o nome do repositório contém apenas caracteres alfabéticos latinos, hifens e sublinhados. Para dar um exemplo completo, o código completo completo server.rb
disponível no repositório complementar para este início rápido inclui tanto o método de validação de recebimento das cargas do webhook quanto esta verificação do nome do repositório.
# This quickstart example uses the repository name in the webhook with
# command-line utilities. For security reasons, you should validate the
# repository name to ensure that a bad actor isn't attempting to execute
# arbitrary commands or inject false repository names. Se um nome de repositório
# for fornecido no webhook, certifique-se de que consiste apenas de
# caracteres alfabéticos latinos `-`, e `_`.
unless @payload['repository'].nil?
halt 400 if (@payload['repository']['name'] =~ /[0-9A-Za-z\-\_]+/).nil?
end
Solução de Problemas
Aqui estão alguns problemas comuns e algumas soluções sugeridas. Se você tiver qualquer outro problema, poderá pedir ajuda ou orientação em Fórum de Suporte e Desenvolvimento de API GitHub.
-
P: Meu aplicativo não está enviando código para o GitHub. Eu não vejo as correções que o RuboCop faz automaticamente!
R: Certifique-se de que você tem permissões de Leitura & gravação para "conteúdo de repositório" e que você está clonando o repositório com seu token de instalação. Consulte Etapa 2.2. Clonar o repositório para obter detalhes.
-
P: Vejo um erro no saída de depuração de
template_server.rb
relacionado à clonagem do meu repositório.R: Se você vir o erro a seguir, você não excluiu o excluiu ou fez o checkout do repositório em um ou ambos os métodos
initiate_check_run
outake_requested_action
:2018-11-26 16:55:13 - Git::GitExecuteError - git clone '--' 'https://x-access-token:v1.9b2080277016f797074c4debd350745f4257f8dd@github.com/codertocat/octocat-breeds.git' 'Octocat-breeds' 2>&1:fatal: o caminho do destino 'Octocat-breeds' já existe e não é um diretório vazio.:
Compare seu código com o arquivo
server.rb
para garantir que você tenha o mesmo código nos seus métodosinitiate_check_run
etake_requested_action
. -
P: As novas execuções de verificação não estão aparecendo na aba "Verificações" no GitHub.
R: Reinicie o Smee e execute novamente o seu servidor
template_server.rb
. -
P: Eu não vejo o botão "Executar tudo novamente" na aba "Verificações" no GitHub.
R: Reinicie o Smee e execute novamente o seu servidor
template_server.rb
.
Conclusão
Depois ler este guia, você aprendeu os princípios básicos para usar a API de verificação para criar um servidor de CI! Para resumir, você:
- Configurou seu servidor para receber eventos de API de verificação e criar execuções de verificação.
- Usou o RuboCop para verificar códigos nos repositórios e criar anotações para os erros.
- Implementou uma ação solicitada que corrige os erros do linter automaticamente.
Próximas etapas
Aqui estão algumas ideias do que você pode fazer a seguir:
- Atualmente, o botão "Corrija isso" sempre é exibido. Atualize o código que você escreveu para exibir o botão "Corrija isso" somente quando o RuboCop encontrar erros.
- Se preferir que RuboCop não comprometa os arquivos diretamente para o branch principal, você pode atualizar o código para criar um pull request com um novo branch baseado no branch principal.