Skip to main content

Scripts com a API REST e o Ruby

Saiba como escrever um script usando o SDK do Octokit.rb para interagir com a API REST.

Sobre o Octokit.rb

Se quiser escrever um script usando o Ruby para interagir com a API REST do GitHub, a GitHub recomenda o uso do SDK Octokit.rb. O Octokit.rb é mantido pela GitHub. O SDK implementa as melhores práticas e facilita a interação com a API REST por meio do Ruby. O Octokit.rb funciona com todos os navegadores modernos, Node.rb e Deno. Para obter mais informações sobre o Octokit.rb, confira o arquivo LEIAME do Octokit.rb.

Pré-requisitos

Este guia pressupõe que você esteja familiarizado com o Ruby e a API REST da GitHub. Para obter informações sobre a API REST, confira "Introdução à API REST".

Você deve instalar e importar a joia octokit para usar a biblioteca Octokit.rb. Este guia usa instruções de importação de acordo com as convenções Ruby. Para obter mais informações sobre os diferentes métodos de instalação, consulte a seção Instalação do LEIAME do Octokit.rb.

Instanciação e autenticação

Aviso: trate suas credenciais de autenticação como uma senha.

Para manter suas credenciais seguras, você pode armazená-las como um segredo e executar seu script por meio de GitHub Actions. Para obter mais informações, confira "Usar segredos em ações do GitHub".

Você também pode armazenar suas credenciais como um segredo do Codespaces e executar seu script no Codespaces. Para obter mais informações, confira "Gerenciando segredos específicos da sua conta para o GitHub Codespaces".

Se essas opções não forem possíveis, considere usar outro serviço CLI para armazenar suas credenciais com segurança.

Autenticar com um personal access token

Se quiser usar a API REST do GitHub para uso pessoal, crie um personal access token. Para obter mais informações sobre como criar um personal access token, confira "Gerenciar seus tokens de acesso pessoal".

Primeiro, exija a biblioteca octokit. Em seguida, crie uma instância de Octokit, passando seu personal access token como a opção access_token. No exemplo a seguir, substitua YOUR-TOKEN pelo seu personal access token.

Ruby
require 'octokit'

octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')

Autenticação com um GitHub App

Se você quiser usar a API em nome de uma organização ou de outro usuário, a GitHub recomenda que você use um GitHub App. Se um ponto de extremidade estiver disponível para GitHub Apps, a documentação de referência da API REST para esse ponto de extremidade indicará que tipo de token do GitHub App é necessário. Para obter mais informações, confira "Registrar um Aplicativo GitHub" e "Sobre a autenticação com um GitHub App."

Em vez de exigir octokit, crie uma instância de Octokit::Client, passando as informações do GitHub App como opções. No exemplo a seguir, substitua APP_ID pelo ID do seu aplicativo, PRIVATE_KEY pela chave privada do seu aplicativo e INSTALLATION_ID pelo ID da instalação do seu aplicativo em nome do qual você deseja autenticar. Você pode encontrar a ID do seu aplicativo e gerar uma chave privada na página de configurações do aplicativo. Para obter mais informações, confira "Como gerenciar chaves privadas para Aplicativos GitHub". Você pode obter uma ID de instalação com os pontos de extremidade GET /users/{username}/installation, GET /repos/{owner}/{repo}/installation ou GET /orgs/{org}/installation. Para obter mais informações, consulte "Pontos de extremidade da API REST para o GitHub Apps."

Ruby
require 'octokit'

app = Octokit::Client.new(
  client_id: APP_ID,
  client_secret: PRIVATE_KEY,
  installation_id: INSTALLATION_ID
)

octokit = Octokit::Client.new(bearer_token: app.create_app_installation.access_token)

Autenticação em GitHub Actions

Se você quiser usar a API em um fluxo de trabalho de GitHub Actions, a GitHub recomenda que você se autentique com o GITHUB_TOKEN interno, em vez de criar um token. Você pode conceder permissões à GITHUB_TOKEN com a chave permissions. Para obter mais informações sobre GITHUB_TOKEN, confira "Autenticação automática de token".

Se o fluxo de trabalho precisar acessar recursos fora do repositório dele, então você não poderá usar GITHUB_TOKEN. Nesse caso, armazene suas credenciais como um segredo e substitua GITHUB_TOKEN nos exemplos abaixo pelo nome do segredo. Para obter mais informações sobre segredos, confira "Usar segredos em ações do GitHub".

Se usar a palavra-chave run para executar o script do Ruby em seus fluxos de trabalho de GitHub Actions, você poderá armazenar o valor de GITHUB_TOKEN como uma variável de ambiente. Seu script pode acessar a variável de ambiente como ENV['VARIABLE_NAME'].

Por exemplo, essa etapa do fluxo de trabalho armazena GITHUB_TOKEN em uma variável de ambiente chamada TOKEN:

- name: Run script
  env:
    TOKEN: ${{ secrets.GITHUB_TOKEN }}
  run: |
    ruby .github/actions-scripts/use-the-api.rb

O script que o fluxo de trabalho executa usa ENV['TOKEN'] para se autenticar:

Ruby
require 'octokit'

octokit = Octokit::Client.new(access_token: ENV['TOKEN'])

Instanciação sem autenticação

Você pode usar a API REST sem autenticação, embora isso forneça um limite de taxa mais baixo e não permita o uso de alguns pontos de extremidade. Para criar uma instância de Octokit sem autenticação, não passe a opção access_token.

Ruby
require 'octokit'

octokit = Octokit::Client.new

Como fazer solicitações

O Octokit dá suporte a várias maneiras de fazer solicitações. Você pode usar o método request para fazer solicitações se souber o verbo HTTP e o caminho para o ponto de extremidade. Você pode usar o método rest se quiser aproveitar o preenchimento automático em seu IDE e digitar. Para pontos de extremidade paginados, você pode usar o método paginate para solicitar várias páginas de dados.

Como usar o método request para fazer solicitações

Para usar o método request a fim de fazer solicitações, passe o método HTTP e o caminho como o primeiro argumento. Passe qualquer parâmetro de corpo, consulta ou caminho em um hash como o segundo argumento. Por exemplo, para fazer uma solicitação GET para /repos/{owner}/{repo}/issues e passar os parâmetros owner, repo e per_page:

Ruby
octokit.request("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)

O método request passa automaticamente o cabeçalho Accept: application/vnd.github+json. Para passar cabeçalhos adicionais ou um cabeçalho Accept diferente, adicione uma opção headers ao hash que é passado como um segundo argumento. O valor da opção headers é um hash com os nomes de cabeçalho como chaves e os valores de cabeçalho como valores. Por exemplo, para enviar um cabeçalho content-type com o valor text/plain:

Ruby
octokit.request("POST /markdown/raw", text: "Hello **world**", headers: { "content-type" => "text/plain" })

Como usar métodos de ponto de extremidade rest para fazer solicitações

Cada ponto de extremidade da API REST tem um método de ponto de extremidade rest associado no Octokit. Esses métodos geralmente são preenchidos automaticamente em seu IDE para conveniência. Você pode passar qualquer parâmetro como um hash para o método.

Ruby
octokit.rest.issues.list_for_repo(owner: "github", repo: "docs", per_page: 2)

Como fazer solicitações paginadas

Se o ponto de extremidade for paginado e você quiser buscar mais de uma página de resultados, poderá usar o método paginate. paginate buscará a próxima página de resultados até chegar à última página e retornará todos os resultados como uma matriz. Alguns pontos de extremidade retornam resultados paginados como matriz em um objeto, em vez de retornar os resultados paginados como uma matriz. paginate sempre retorna uma matriz de itens, mesmo que o resultado bruto tenha sido um objeto .

Por exemplo, o caso a seguir obtém todos os problemas do repositório github/docs. Embora solicite 100 solicitações por vez, a função não retornará até que a última página de dados seja atingida.

Ruby
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)

O método paginate aceita um bloco opcional, que você pode usar para processar cada página de resultados. Isso permite coletar apenas os dados desejados da resposta. Por exemplo, o caso a seguir segue buscando resultados até que seja retornado um problema com "teste" no título. Para as páginas de dados que foram retornadas, são armazenados apenas o título e o autor do problema.

Ruby
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100) do |response, done|
  response.data.map do |issue|
    if issue.title.include?("test")
      done.call
    end
    { title: issue.title, author: issue.user.login }
  end
end

Em vez de buscar todos os resultados de uma só vez, você pode usar octokit.paginate.iterator() para percorrer uma só página de cada vez. Por exemplo, o caso a seguir busca uma página de resultados por vez e processa cada objeto da página atual antes de buscar a próxima. Uma vez encontrado um problema com "teste" no título, o script interrompe a iteração e retorna o título e o autor do problema de cada objeto que foi processado. O iterador é o método mais eficiente em termos de memória para buscar dados paginados.

Ruby
iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
issue_data = []
break_loop = false
iterator.each do |data|
  break if break_loop
  data.each do |issue|
    if issue.title.include?("test")
      break_loop = true
      break
    else
      issue_data << { title: issue.title, author: issue.user.login }
    end
  end
end

Você também pode usar o método paginate com os métodos de ponto de extremidade rest. Passe o método de ponto de extremidade rest como o primeiro argumento e quaisquer parâmetros como o segundo argumento.

Ruby
iterator = octokit.paginate.iterator(octokit.rest.issues.list_for_repo, owner: "github", repo: "docs", per_page: 100)

Para obter mais informações sobre paginação, confira "Como usar paginação na API REST".

Captura de erros

Capturando todos os erros

Às vezes, a API REST da GitHub retorna um erro. Por exemplo, um erro será exibido se o token de acesso tiver expirado ou se um parâmetro obrigatório for omitido. O Octokit.rb faz automaticamente novas tentativas de executar a solicitação quando obtém um erro diferente de 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found ou 422 Unprocessable Entity. Se ocorrer um erro de API mesmo após novas tentativas, o Octokit.rb gera um erro que inclui o código de status HTTP da resposta (response.status) e os cabeçalhos da resposta (response.headers). Você deve tratar esses erros em seu código. Por exemplo, você pode usar um bloco try/catch para capturar erros:

Ruby
begin
files_changed = []

iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", owner: "github", repo: "docs", pull_number: 22809, per_page: 100)
iterator.each do | data |
    files_changed.concat(data.map {
      | file_data | file_data.filename
    })
  end
rescue Octokit::Error => error
if error.response
puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
end
puts error
end

Tratamento de códigos de erro previstos

Às vezes, a GitHub usa um código de status 4xx para indicar uma resposta sem erro. Se o ponto de extremidade que você está usando fizer isso, você poderá adicionar tratamentos adicionais para erros específicos. Por exemplo, o ponto de extremidade GET /user/starred/{owner}/{repo} retornará 404 se o repositório não for estrelado. O exemplo a seguir usa a resposta 404 para indicar que o repositório não foi estrelado; todos os demais códigos de erros são tratados como erros.

Ruby
begin
octokit.request("GET /user/starred/{owner}/{repo}", owner: "github", repo: "docs")
puts "The repository is starred by me"
rescue Octokit::NotFound => error
puts "The repository is not starred by me"
rescue Octokit::Error => error
puts "An error occurred while checking if the repository is starred: #{error&.response&.data&.message}"
end

Tratamento de erros de limite de taxa

Se você receber um erro de limite de taxa, talvez seja necessário repetir a solicitação após aguardar um tempo. Quando você tem taxa limitada, a GitHub responde com um erro 403 Forbidden e o valor do cabeçalho de resposta x-ratelimit-remaining será "0". Os cabeçalhos de resposta incluirão um cabeçalho x-ratelimit-reset, que informa a hora em que a janela de limite de taxa atual é redefinida, em segundos UTC. Você pode repetir a solicitação após aguardar o tempo especificado por x-ratelimit-reset.

Ruby
def request_retry(route, parameters)
 begin
 response = octokit.request(route, parameters)
 return response
 rescue Octokit::RateLimitExceeded => error
 reset_time_epoch_seconds = error.response.headers['x-ratelimit-reset'].to_i
 current_time_epoch_seconds = Time.now.to_i
 seconds_to_wait = reset_time_epoch_seconds - current_time_epoch_seconds
 puts "You have exceeded your rate limit. Retrying in #{seconds_to_wait} seconds."
 sleep(seconds_to_wait)
 retry
 rescue Octokit::Error => error
 puts error
 end
 end

 response = request_retry("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)

Como usar a resposta

O método request retornará um objeto de resposta se a solicitação tiver sido bem-sucedida. O objeto de resposta contém data (o corpo da resposta retornado pelo ponto de extremidade), status (o código de resposta HTTP), url (a URL da solicitação) e headers (um hash que contém os cabeçalhos da resposta). A menos que especificado de outra forma, o corpo da resposta está no formato JSON. Alguns pontos de extremidade não retornam um corpo de resposta; nesses casos, a propriedade data é omitida.

Ruby
response = octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}", owner: "github", repo: "docs", issue_number: 11901)
 puts "The status of the response is: #{response.status}"
 puts "The request URL was: #{response.url}"
 puts "The x-ratelimit-remaining response header is: #{response.headers['x-ratelimit-remaining']}"
 puts "The issue title is: #{response.data['title']}"

Da mesma forma, o método paginate retorna um objeto de resposta. Se o request for bem-sucedido, o objeto response conterá dados, status, URL e cabeçalhos.

Ruby
response = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
puts "#{response.data.length} issues were returned"
puts "The title of the first issue is: #{response.data[0]['title']}"

Script de exemplo

Aqui está um script de exemplo completo que usa o Octokit.rb. O script importa Octokit e cria uma instância de Octokit. Se você quiser se autenticar com um GitHub App em vez de um personal access token, importe e instancie App em vez de Octokit. Para obter mais informações, confira "Como se autenticar com um GitHub App", neste guia.

A função get_changed_files obtém todos os arquivos alterados para uma solicitação de pull. A função comment_if_data_files_changed chama a função get_changed_files. Se qualquer um dos arquivos que a solicitação de pull alterou incluir /data/ no caminho, a função comentará sobre a solicitação de pull.

Ruby
require "octokit"

 octokit = Octokit::Client.new(access_token: "YOUR-TOKEN")

 def get_changed_files(octokit, owner, repo, pull_number)
 files_changed = []

 begin
 iterator = octokit.paginate.iterator("GET /repos/{owner}/{repo}/pulls/{pull_number}/files", owner: owner, repo: repo, pull_number: pull_number, per_page: 100)
 iterator.each do | data |
     files_changed.concat(data.map {
       | file_data | file_data.filename
     })
   end
 rescue Octokit::Error => error
 if error.response
 puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
 end
 puts error
 end

 files_changed
 end

 def comment_if_data_files_changed(octokit, owner, repo, pull_number)
 changed_files = get_changed_files(octokit, owner, repo, pull_number)

 if changed_files.any ? {
   | file_name | /\/data\//i.match ? (file_name)
 }
 begin
 comment = octokit.create_pull_request_review_comment(owner, repo, pull_number, "It looks like you changed a data file. These files are auto-generated. \n\nYou must revert any changes to data files before your pull request will be reviewed.")
 comment.html_url
 rescue Octokit::Error => error
 if error.response
 puts "Error! Status: #{error.response.status}. Message: #{error.response.data.message}"
 end
 puts error
 end
 end
 end

# Example usage
owner = "github"
repo = "docs"
pull_number = 22809
comment_url = comment_if_data_files_changed(octokit, owner, repo, pull_number)

puts "A comment was added to the pull request: #{comment_url}"

Observação: este é apenas um exemplo básico. Na prática, talvez você queira usar tratamento de erros e verificações condicionais para lidar com vários cenários.

Próximas etapas

Para saber mais sobre como trabalhar com a API REST da GitHub e o Octokit.rb, explore os seguintes recursos: