Skip to main content

Скриптирование с помощью REST API и Ruby

Узнайте, как писать скрипт с помощью пакета SDK octokit.rb для взаимодействия с REST API.

О Octokit.rb

Если вы хотите написать скрипт с помощью Ruby для взаимодействия с REST API GitHub, GitHub рекомендует использовать пакет SDK octokit.rb. Octokit.rb поддерживается GitHub. Пакет SDK реализует рекомендации и упрощает взаимодействие с REST API через Ruby. Octokit.rb работает со всеми современными браузерами, Node.rb и Deno. Дополнительные сведения о Octokit.rb см . в разделе Octokit.rb README.

Необходимые компоненты

В этом руководстве предполагается, что вы знакомы с Ruby и REST API GitHub. Дополнительные сведения о REST API см. в разделе Начало работы с REST API.

Чтобы использовать библиотеку Octokit.rb, необходимо установить и импортировать драгоценный octokit камень. В этом руководстве используются инструкции импорта в соответствии с соглашениями Ruby. Дополнительные сведения о различных методах установки см . в разделе установки Octokit.rb README.

Создание экземпляров и проверка подлинности

Warning

Обработайте учетные данные проверки подлинности как пароль.

Чтобы обеспечить безопасность учетных данных, вы можете хранить свои учетные данные в виде секрета и запускать скрипт с помощью GitHub Actions. Дополнительные сведения см. в разделе Использование секретов в GitHub Actions.

Вы также можете хранить свои учетные данные в виде секрета Codespaces и запустить скрипт в Codespaces. Дополнительные сведения см. в разделе Управление секретами конкретной учетной записи для GitHub Codespaces.

Если эти параметры недоступны, попробуйте использовать другую службу CLI для безопасного хранения учетных данных.

Проверка подлинности с помощью personal access token

Если вы хотите использовать REST API GitHub для личного использования, можно создать personal access token. Дополнительные сведения о создании personal access tokenсм. в разделе Управление личными маркерами доступа.

Сначала требуется octokit библиотека. Затем создайте экземпляр Octokit , передав personal access token в качестве access_token параметра. В следующем примере замените YOUR-TOKEN данные personal access token.

Ruby
require 'octokit'

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

Проверка подлинности с помощью GitHub App

Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендует использовать GitHub App. Если конечная точка доступна для GitHub Apps, справочная документация REST для этой конечной точки будет указывать тип маркера GitHub App. Дополнительные сведения см. в разделе [AUTOTITLE и Регистрация приложения GitHub](/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app).

Вместо необходимости octokitсоздайте экземпляр Octokit::Client , передав данные GitHub Appв качестве параметров. В следующем примере замените APP_ID идентификатором приложения, PRIVATE_KEY закрытым ключом приложения и INSTALLATION_ID идентификатором установки приложения, от имени которого требуется пройти проверку подлинности. Идентификатор приложения можно найти и создать закрытый ключ на странице параметров приложения. Дополнительные сведения см. в разделе Управление закрытыми ключами для приложений GitHub. Идентификатор установки можно получить с GET /users/{username}/installationпомощью конечных точек или GET /orgs/{org}/installation конечных GET /repos/{owner}/{repo}/installationточек. Дополнительные сведения см. в разделе Конечные точки REST API для GitHub Apps.{ %ifversion ghes %} Замените HOSTNAME именем GitHub.com.{ % endif %}

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)

Проверка подлинности в GitHub Actions

Если вы хотите использовать API в рабочем процессе GitHub Actions, GitHub рекомендует выполнять проверку подлинности с помощью встроенного GITHUB_TOKEN вместо создания маркера. Вы можете предоставить разрешения для GITHUB_TOKEN с помощью ключа permissions. Дополнительные сведения см. в GITHUB_TOKENразделе Автоматическая проверка подлинности токенов.

Если рабочий процесс должен получить доступ к ресурсам за пределами репозитория рабочего процесса, вы не сможете использовать GITHUB_TOKEN. В этом случае сохраните свои учетные данные в виде секрета и замените GITHUB_TOKEN в приведенных ниже примерах именем секрета. Дополнительные сведения о секретах см. в разделе Использование секретов в GitHub Actions.

Если вы используете ключевое run слово для выполнения скрипта Ruby в рабочих процессах GitHub Actions, можно сохранить значение GITHUB_TOKEN в виде переменной среды. Скрипт может получить доступ к переменной среды как ENV['VARIABLE_NAME'].

Например, этот шаг рабочего процесса сохраняется GITHUB_TOKEN в переменной среды:TOKEN

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

Скрипт, который ENV['TOKEN'] выполняется рабочим процессом для проверки подлинности:

Ruby
require 'octokit'

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

Создание экземпляров без проверки подлинности

REST API можно использовать без проверки подлинности, хотя у вас будет более низкий предел скорости и не удастся использовать некоторые конечные точки. Чтобы создать экземпляр без проверки подлинности Octokit , не передайте access_token этот параметр.

Ruby
require 'octokit'

octokit = Octokit::Client.new

Выполнение запросов

Octokit поддерживает несколько способов выполнения запросов. Метод можно использовать request для выполнения запросов, если вы знаете HTTP-команду и путь к конечной точке. Этот метод можно использовать, если вы хотите воспользоваться rest преимуществами автозаполнения в интегрированной среде разработки и вводе. Для конечных точек с разбивкой на страницы можно использовать paginate метод для запроса нескольких страниц данных.

request Использование метода для выполнения запросов

Чтобы использовать метод для выполнения запросов, передайте request метод HTTP и путь в качестве первого аргумента. Передайте все параметры текста, запроса или пути в хэш в качестве второго аргумента. Например, чтобы выполнить GET запрос к /repos/{owner}/{repo}/issues и передать параметрыrepo``owner, и per_page выполнить следующие параметры:

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

Метод request автоматически передает Accept: application/vnd.github+json заголовок. Чтобы передать дополнительные заголовки или другой Accept заголовок, добавьте headers параметр в хэш, передаваемый в качестве второго аргумента. Значение headers параметра — хэш с именами заголовков в качестве ключей и значений заголовков в качестве значений. Например, чтобы отправить заголовок content-type со значением text/plain:

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

Использование rest методов конечной точки для выполнения запросов

Каждая конечная точка REST API имеет связанный rest метод конечной точки в Octokit. Эти методы обычно автоматически заполняются в интегрированной среде разработки для удобства. В метод можно передать любые параметры в виде хэша.

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

Выполнение запросов с разбивкой на страницы

Если конечная точка разбина на страницы и вы хотите получить несколько страниц результатов, можно использовать paginate этот метод. paginate Возвращает следующую страницу результатов, пока не достигнет последней страницы, а затем возвращает все результаты в виде массива. Несколько конечных точек возвращают результаты с разбивкой на страницы в виде массива в объекте, а не возвращать результаты с разбивкой на страницы в виде массива. paginate всегда возвращает массив элементов, даже если необработанный результат был объектом.

Например, следующий пример получает все проблемы из github/docs репозитория. Хотя она запрашивает 100 проблем за раз, функция не возвращается до достижения последней страницы данных.

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

Метод paginate принимает необязательный блок, который можно использовать для обработки каждой страницы результатов. Это позволяет собирать только нужные данные из ответа. Например, следующий пример продолжает получение результатов до тех пор, пока не будет возвращена проблема, содержащая "test" в заголовке. Для страниц возвращаемых данных хранятся только название проблемы и автор.

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

Вместо одновременного получения всех результатов можно использовать octokit.paginate.iterator() для итерации по одной странице за раз. Например, следующий пример извлекает одну страницу результатов за раз и обрабатывает каждый объект из страницы перед получением следующей страницы. После достижения проблемы, включающей "test" в заголовок, скрипт останавливает итерацию и возвращает заголовок проблемы и автор проблемы каждого обработанного объекта. Итератор — это наиболее эффективный метод для получения данных с разбивкой на страницы.

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

Этот paginate метод также можно использовать с методами конечной rest точки. Передайте метод конечной точки в качестве первого аргумента rest и любые параметры в качестве второго аргумента.

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

Дополнительные сведения о разбиении на страницы см. в разделе Использование разбиения на страницы в REST API.

выявления ошибок;

Перехват всех ошибок

Иногда REST API GitHub возвращает ошибку. Например, вы получите ошибку, если срок действия маркера доступа истек или если не указан обязательный параметр. Octokit.rb автоматически повторяет запрос при получении ошибки, отличной от 400 Bad Request, 401 Unauthorized, и 403 Forbidden``404 Not Found.422 Unprocessable Entity Если ошибка API возникает даже после повторных попыток, Octokit.rb выдает ошибку, содержащую код состояния HTTP ответа (response.status) и заголовки ответа (response.headers). Эти ошибки следует обрабатывать в коде. Например, для перехвата ошибок можно использовать блок try/catch:

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

Обработка предполагаемых кодов ошибок

Иногда GitHub использует код состояния 4xx для указания ответа без ошибок. Если используется эта конечная точка, можно добавить дополнительную обработку для определенных ошибок. Например, конечная GET /user/starred/{owner}/{repo} точка вернет объект, 404 если репозиторий не указан. В следующем примере используется ответ, указывающий, что репозиторий 404 не был указан в главной роли. Все остальные коды ошибок рассматриваются как ошибки.

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

Обработка ошибок ограничения скорости

Если вы получаете ошибку ограничения скорости, вы можете повторить запрос после ожидания. Если скорость ограничена, GitHub отвечает ошибкой403 Forbidden, а x-ratelimit-remaining значение заголовка ответа будет."0" Заголовки ответа будут содержать x-ratelimit-reset заголовок, который указывает время сброса текущего ограничения скорости в секундах эпохи UTC. После указанного 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)

Использование ответа

Метод request возвращает объект ответа, если запрос выполнен успешно. Объект ответа содержит data (текст ответа, возвращаемый конечной точкой), status (код ответа HTTP), url (URL-адрес запроса) и headers (хэш, содержащий заголовки ответа). Если не указано иное, текст ответа имеет формат JSON. Некоторые конечные точки не возвращают текст ответа; В этих случаях data свойство опущено.

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']}"

Аналогичным образом paginate метод возвращает объект ответа. В случае успешного request выполнения response объект содержит данные, состояние, URL-адрес и заголовки.

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']}"

Пример сценария

Ниже приведен полный пример скрипта, использующего Octokit.rb. Скрипт импортирует Octokit и создает новый экземпляр Octokit. Если вы хотите выполнить проверку подлинности с помощью GitHub App, а не personal access token, вы импортируете и создайте экземпляр App вместо Octokitнего. Дополнительные сведения см. в руководстве по проверке подлинности с помощью GitHub App в этом руководстве.

Функция get_changed_files получает все файлы, измененные для запроса на вытягивание. Функция comment_if_data_files_changed вызывает функцию get_changed_files . Если любой из файлов, измененных запросом на вытягивание, включен /data/ в путь к файлу, функция будет комментировать запрос на вытягивание.

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}"

Note

Это просто базовый пример. На практике может потребоваться использовать обработку ошибок и условные проверки для обработки различных сценариев.

Следующие шаги

Дополнительные сведения о работе с API REST API GitHub и Octokit.rb см. в следующих ресурсах:

  • Дополнительные сведения о Octokit.rb см . в документации по Octokit.rb.
  • Подробные сведения о доступных конечных точках REST API % variables.product.company_short %}, включая структуры запросов и ответов, см. в разделе AUTOTITLE.