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

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

## О Octokit.rb

Если вы хотите написать скрипт с помощью Ruby для взаимодействия с GitHub REST API, GitHub рекомендуется использовать пакет SDK octokit.rb. Octokit.rb поддерживается GitHub. Пакет SDK реализует рекомендации и упрощает взаимодействие с REST API через Ruby. Octokit.rb работает со всеми современными браузерами, Node.rb и Deno. Дополнительные сведения о Octokit.rb см [. в разделе Octokit.rb README](https://github.com/octokit/octokit.rb/#readme).

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

В этом руководстве предполагается, что вы знакомы с Ruby и GitHub REST API. Дополнительные сведения о REST API см. в разделе [Начало работы с REST API](/ru/rest/using-the-rest-api/getting-started-with-the-rest-api).

Чтобы использовать библиотеку Octokit.rb, необходимо установить и импортировать драгоценный `octokit` камень. В этом руководстве используются инструкции импорта в соответствии с соглашениями Ruby. Дополнительные сведения о различных методах установки см [. в разделе](https://github.com/octokit/octokit.rb/#installation) установки Octokit.rb README.

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

> \[!WARNING]
> Обработайте учетные данные проверки подлинности как пароль.
>
> Чтобы обеспечить безопасность учетных данных, вы можете сохранить свои учетные данные в виде секрета и запустить скрипт.GitHub Actions Дополнительные сведения см. в разделе [Использование секретов в GitHub Actions](/ru/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets).

> Вы также можете сохранить свои учетные данные в виде секрета Codespaces и запустить скрипт в Codespaces. Дополнительные сведения см. в разделе [Управление секретами, специфичными для ваших аккаунтов, для GitHub Codespaces](/ru/codespaces/managing-your-codespaces/managing-your-account-specific-secrets-for-github-codespaces).

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

### Аутентификация с помощью personal access token

Если вы хотите использовать GitHub REST API для личного использования, вы можете создать personal access token. Для получения дополнительной информации о создании personal access token, см. [Управление личными маркерами доступа](/ru/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).

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

```ruby copy
require 'octokit'

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

### Аутентификация с помощью GitHub App

Если вы хотите использовать API от имени организации или другого пользователя, GitHub рекомендуется использовать GitHub App. Если конечная точка доступна GitHub Apps, справочная документация REST для этой конечной точки будет указывать, какой тип маркера GitHub App является обязательным. Дополнительные сведения см. в разделе \[AUTOTITLE и [Регистрация приложения GitHub](/ru/apps/creating-github-apps/registering-a-github-app/registering-a-github-app)]\(/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](/ru/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps). Идентификатор установки можно получить с `GET /users/{username}/installation`помощью конечных точек или `GET /repos/{owner}/{repo}/installation` конечных `GET /orgs/{org}/installation`точек. Для получения дополнительной информации см. [Конечные точки REST API для GitHub Apps](/ru/rest/apps/apps).

```ruby copy
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](/ru/actions/concepts/security/github_token).

Если рабочий процесс должен получить доступ к ресурсам за пределами репозитория рабочего процесса, вы не сможете использовать `GITHUB_TOKEN`. В этом случае сохраните свои учетные данные в виде секрета и замените `GITHUB_TOKEN` в приведенных ниже примерах именем секрета. Дополнительные сведения о секретах см. в разделе [Использование секретов в GitHub Actions](/ru/actions/how-tos/write-workflows/choose-what-workflows-do/use-secrets).

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

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

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

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

```ruby copy
require 'octokit'

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

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

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

```ruby copy
require 'octokit'

octokit = Octokit::Client.new
```

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

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

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

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

```ruby copy
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 copy
octokit.request("POST /markdown/raw", text: "Hello **world**", headers: { "content-type" => "text/plain" })
```

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

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

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

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

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

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

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

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

```ruby copy
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 copy
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 copy
iterator = octokit.paginate.iterator(octokit.rest.issues.list_for_repo, owner: "github", repo: "docs", per_page: 100)
```

Дополнительные сведения о разбиении на страницы см. в разделе [Использование разбиения на страницы в REST API](/ru/rest/using-the-rest-api/using-pagination-in-the-rest-api).

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

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

GitHub Иногда REST API возвращает ошибку. Например, вы получите ошибку, если срок действия маркера доступа истек или если не указан обязательный параметр. 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 copy
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 copy
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
```

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

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

```ruby copy
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 copy
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 copy
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по проверке подлинности](#authenticating-with-a-github-app).

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

```ruby copy
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]
> Это просто базовый пример. На практике может потребоваться использовать обработку ошибок и условные проверки для обработки различных сценариев.

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

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

* Дополнительные сведения о Octokit.rb см [. в документации](https://github.com/octokit/octokit.rb/#readme) по Octokit.rb.
* Подробные сведения о GitHubдоступных конечных точках REST API, включая структуры запросов и ответов, см. в разделе [Документация по GitHub REST API](/ru/rest).