À propos d’Octokit.rb
Si vous souhaitez écrire un script avec Ruby pour interagir avec l’API REST de GitHub, GitHub vous recommande d’utiliser le SDK Octokit.rb. Octokit.rb est maintenu par GitHub. Le SDK implémente les meilleures pratiques et vous permet d’interagir plus facilement avec l’API REST via Ruby. Octokit.rb fonctionne avec tous les navigateurs modernes, Node.rb et Deno. Pour plus d’informations sur Octokit.rb, consultez le fichier LISEZMOI Octokit.rb.
Prérequis
Ce guide suppose que vous êtes familiarisé avec Ruby et l’API REST GitHub REST API. Pour plus d’informations sur l’API REST, consultez « Prise en main de l’API REST ».
Vous devez installer et importer le gemme octokit
pour utiliser la bibliothèque Octokit.rb. Ce guide utilise des instructions import conformément aux conventions Ruby. Pour plus d’informations sur les différentes méthodes d’installation, consultez la section d’installation du fichier LISEZMOI Octokit.rb.
Instanciation et authentification
Avertissement : Gérez vos informations d’authentification comme un mot de passe.
Pour que vos informations d’identification restent sécurisées, vous pouvez les stocker sous forme de secret et exécuter votre script par le biais de GitHub Actions. Pour plus d’informations, consultez « Utilisation de secrets dans GitHub Actions ».
Vous pouvez aussi stocker vos informations d’identification sous forme de secret Codespaces et exécuter votre script dans Codespaces. Pour plus d’informations, consultez « Gestion des secrets spécifiques à votre compte pour GitHub Codespaces ».
Si ces options ne sont pas possibles, envisagez d’utiliser un autre service CLI pour stocker vos informations d’identification de façon sécurisée.
Authentification avec un personal access token
Si vous voulez utiliser l’API REST GitHub à des fins personnelles, vous pouvez créer un personal access token. Pour plus d’informations sur la création d’un personal access token, consultez « Gestion de vos jetons d'accès personnels ».
Tout d’abord, exigez la bibliothèque octokit
. Ensuite, créez une instance de Octokit
en faisant passer votre personal access token comme l’option access_token
. Dans l’exemple suivant, remplacez YOUR-TOKEN
par vos personal access token.
require 'octokit' octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')
require 'octokit'
octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')
Authentification avec une GitHub App
Si vous voulez utiliser l’API au nom d’une organisation ou d’un autre utilisateur, GitHub vous recommande d’utiliser une GitHub App. Si un point de terminaison est disponible pour GitHub Apps, la documentation de référence de REST pour ce point de terminaison indique quel type de jeton GitHub App est nécessaire. Pour plus d’informations, consultez « Inscription d’une application GitHub » et « À propos de l’authentification avec une application GitHub ».
Au lieu d’exiger octokit
, créez une instance de Octokit::Client
en transmettant vos informations GitHub App en tant qu’options. Dans l’exemple suivant, remplacez APP_ID
par l’ID d’application, PRIVATE_KEY
avec la clé privée de votre application et INSTALLATION_ID
avec l’ID de l’installation de votre application pour laquelle vous souhaitez vous authentifier. Vous pouvez trouver l’ID de votre application et générer une clé privée dans la page des paramètres de votre application. Pour plus d’informations, consultez « Gestion des clés privées pour les applications GitHub ». Vous pouvez obtenir un ID d’installation avec les points de terminaison GET /users/{username}/installation
, GET /repos/{owner}/{repo}/installation
ou GET /orgs/{org}/installation
. Pour plus d’informations, consultez « AUTOTITRE »."
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)
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)
Authentification dans GitHub Actions
Si vous voulez utiliser l’API dans un workflow GitHub Actions, GitHub vous recommande d’être authentifié avec le jeton GITHUB_TOKEN
intégré au lieu de créer un jeton. Vous pouvez accorder des autorisations au GITHUB_TOKEN
avec la clé permissions
. Pour plus d’informations sur GITHUB_TOKEN
, consultez « Authentification par jeton automatique ».
Si votre workflow doit accéder à des ressources en dehors du dépôt du workflow, vous ne pourrez pas utiliser GITHUB_TOKEN
. Dans ce cas, stockez vos informations d’identification sous forme de secret et remplacez GITHUB_TOKEN
dans les exemples ci-dessous par le nom de votre secret. Pour plus d’informations sur les secrets, consultez « Utilisation de secrets dans GitHub Actions ».
Si vous utilisez le mot clé run
pour exécuter votre script Ruby dans vos flux de travail GitHub Actions, vous pouvez stocker la valeur de GITHUB_TOKEN
en tant que variable d’environnement. Votre script peut accéder à la variable d’environnement en tant que ENV['VARIABLE_NAME']
.
Par exemple, cette étape de workflow stocke GITHUB_TOKEN
dans une variable d’environnement appelée TOKEN
:
- name: Run script
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ruby .github/actions-scripts/use-the-api.rb
Le script qu’exécute le workflow utilise ENV['TOKEN']
pour l’authentification :
require 'octokit' octokit = Octokit::Client.new(access_token: ENV['TOKEN'])
require 'octokit'
octokit = Octokit::Client.new(access_token: ENV['TOKEN'])
Instanciation sans authentification
Vous pouvez utiliser l’API REST sans authentification, mais vous aurez une limite de débit inférieure et vous ne pourrez pas utiliser certains points de terminaison. Pour créer une instance de Octokit
sans authentification, n’ignorez pas l’option access_token
.
require 'octokit' octokit = Octokit::Client.new
require 'octokit'
octokit = Octokit::Client.new
Création de requêtes
Octokit prend en charge plusieurs façons de créer des requêtes. Vous pouvez utiliser la méthode request
pour créer des requêtes si vous connaissez le verbe HTTP et le chemin du point de terminaison. Vous pouvez utiliser la méthode rest
si vous souhaitez tirer parti de l’autocomplétion dans votre IDE et de la saisie. Pour les points de terminaison paginés, vous pouvez utiliser la méthode paginate
pour demander plusieurs pages de données.
Utilisation de la méthode request
pour créer des requêtes
Pour utiliser la méthode request
pour créer des requêtes, passez la méthode HTTP et le chemin comme premier argument. Passez tous les paramètres de corps, de requête ou de chemin d’accès dans un code de hachage en tant que deuxième argument. Par exemple, pour créer une requête GET
dans /repos/{owner}/{repo}/issues
et passer les paramètres owner
, repo
et per_page
:
octokit.request("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)
octokit.request("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 2)
La méthode request
passe automatiquement l’en-tête Accept: application/vnd.github+json
. Pour passer des en-têtes supplémentaires ou un en-tête Accept
différent, ajoutez une option headers
au code de hachage passé en tant que deuxième argument. La valeur de l’option headers
est un code de hachage avec les noms d’en-tête en tant que clés et les valeurs d’en-tête en tant que valeurs. Par exemple, pour envoyer un en-tête content-type
avec la valeur de text/plain
:
octokit.request("POST /markdown/raw", text: "Hello **world**", headers: { "content-type" => "text/plain" })
octokit.request("POST /markdown/raw", text: "Hello **world**", headers: { "content-type" => "text/plain" })
Utilisation des méthodes de point de terminaison rest
pour créer des requêtes
Chaque point de terminaison d’API REST a une méthode de point de terminaison rest
associée dans Octokit. Ces méthodes appliquent généralement l’autocomplétion dans votre IDE pour des raisons pratiques. Vous pouvez passer n’importe quel paramètre en tant code de hachage à la méthode.
octokit.rest.issues.list_for_repo(owner: "github", repo: "docs", per_page: 2)
octokit.rest.issues.list_for_repo(owner: "github", repo: "docs", per_page: 2)
Création de requêtes paginées
Si le point de terminaison est paginé et que vous souhaitez extraire plusieurs pages de résultats, vous pouvez utiliser la méthode paginate
. paginate
récupère la page de résultats suivante jusqu’à atteindre la dernière page, puis retourne tous les résultats sous la forme d’un tableau. Quelques points de terminaison retournent les résultats paginés sous forme de tableau dans un objet, au lieu de les retourner sous forme de tableau. paginate
retourne toujours un tableau d’éléments même si le résultat brut était un objet.
Par exemple, l’exemple suivant récupère tous les problèmes du dépôt github/docs
. Bien qu’elle demande 100 problèmes à la fois, la fonction n’est pas retournée tant que la dernière page de données n’est pas atteinte.
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
issue_data = octokit.paginate("GET /repos/{owner}/{repo}/issues", owner: "github", repo: "docs", per_page: 100)
La méthode paginate
accepte un bloc facultatif, que vous pouvez utiliser pour traiter chaque page de résultats. Cela vous permet de collecter uniquement les données souhaitées à partir de la réponse. Par exemple, l’exemple suivant continue d’extraire les résultats jusqu’à ce qu’un problème incluant « test » dans le titre soit retourné. Pour les pages de données qui ont été retournées, seuls le titre et l’auteur du problème sont stockés.
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
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
Au lieu d’extraire tous les résultats à la fois, vous pouvez utiliser octokit.paginate.iterator()
pour itérer au sein d’une seule page à la fois. Par exemple, l’exemple suivant extrait une page de résultats à la fois et traite chaque objet de la page avant d’extraire la page suivante. Une fois qu’un problème qui inclut « test » dans le titre est atteint, le script arrête l’itération et retourne le titre du problème et l’auteur du problème de chaque objet qui a été traité. L’itérateur est la méthode la plus efficace en mémoire pour extraire des données paginées.
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
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
Vous pouvez également utiliser la méthode paginate
avec les méthodes de point de terminaison rest
. Transmettez la méthode de point de terminaison rest
en tant que premier argument et tous les paramètres comme deuxième argument.
iterator = octokit.paginate.iterator(octokit.rest.issues.list_for_repo, owner: "github", repo: "docs", per_page: 100)
iterator = octokit.paginate.iterator(octokit.rest.issues.list_for_repo, owner: "github", repo: "docs", per_page: 100)
Pour plus d’informations sur la pagination, consultez « Utilisation de la pagination dans l’API REST ».
Interception des erreurs
Interception de toutes les erreurs
Parfois, l’API REST GitHub retourne une erreur. Par exemple, vous obtenez une erreur si votre jeton d’accès a expiré ou si vous avez omis un paramètre obligatoire. Octokit.rb retente automatiquement la demande quand il obtient une erreur autre que 400 Bad Request
, 401 Unauthorized
, 403 Forbidden
, 404 Not Found
et 422 Unprocessable Entity
. Si une erreur d’API se produit même après plusieurs tentatives, Octokit.rb lève une erreur qui inclut le code d’état HTTP de la réponse (response.status
) et les en-têtes de réponse (response.headers
). Vous devez gérer ces erreurs dans votre code. Par exemple, vous pouvez utiliser un bloc try/catch pour intercepter les erreurs :
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
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
Gestion des codes d’erreur prévus
Parfois, GitHub utilise un code d’état 4xx pour indiquer une réponse de non-erreur. Si le point de terminaison que vous utilisez le fait, vous pouvez ajouter une gestion supplémentaire pour des erreurs spécifiques. Par exemple, le point de terminaison GET /user/starred/{owner}/{repo}
retourne une erreur 404
si le dépôt n’a pas d’étoile. L’exemple suivant utilise la réponse 404
pour indiquer que le référentiel n’est pas marqué d’étoile, tous les autres codes d’erreur sont traités comme des erreurs.
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
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
Gestion des erreurs de limite de débit
Si vous recevez une erreur de limite de débit, vous pouvez retenter votre demande après avoir attendu. Quand votre taux est limité, GitHub répond avec une erreur 403 Forbidden
et la valeur d’en-tête de réponse x-ratelimit-remaining
sera "0"
. Les en-têtes de réponse incluent un en-tête x-ratelimit-reset
, qui vous indique l’heure à laquelle la fenêtre de limite de débit actuelle est réinitialisée, en secondes d’époque UTC. Vous pouvez retenter votre demande après l’heure spécifiée par x-ratelimit-reset
.
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)
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)
Utilisation de la réponse
La méthode request
retourne un objet de réponse si la demande a réussi. L’objet de réponse contient data
(le corps de la réponse retourné par le point de terminaison), status
(le code de réponse HTTP), url
(l’URL de la requête) et headers
(un code de hachage contenant les en-têtes de réponse). Sauf indication contraire, le corps de réponse est au format JSON. Certains points de terminaison ne retournent pas de corps de réponse, auquel cas, la propriété data
est omise.
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']}"
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']}"
De même, la méthode paginate
retourne un objet de réponse. Si request
a réussi, l’objet response
contient des données, un état, une URL et des en-têtes.
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']}"
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']}"
Exemple de script
Voici un exemple de script complet qui utilise Octokit.rb. Le script importe Octokit
et crée une nouvelle instance Octokit
. Si vous souhaitez vous authentifier avec une GitHub App au lieu d’un personal access token, vous devez importer et instancier App
à la place de Octokit
. Pour plus d’informations, consultez « Authentification avec un(e) GitHub App » dans ce guide.
La fonction get_changed_files
obtient tous les fichiers modifiés pour une demande de tirage. La fonction comment_if_data_files_changed
appelle la fonction get_changed_files
. Si l’un des fichiers modifiés par la demande de tirage inclut /data/
dans le chemin, la fonction commente la demande de tirage.
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}"
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}"
Remarque : il s’agit simplement d’un exemple de base. Dans la pratique, vous pouvez utiliser la gestion des erreurs et les examens conditionnelles pour gérer différents scénarios.
Étapes suivantes
Pour en savoir plus sur l’utilisation de l’API REST GitHub et Octokit.rb, explorez les ressources suivantes :
- Pour en savoir plus sur Octokit.rb, consultez la documentation Octokit.rb.
- Pour obtenir des informations détaillées sur les points de terminaison d’API REST disponibles de GitHub, y compris leurs structures de requête et de réponse, consultez Documentation sur l’API REST GitHub.