Octokit.rb 정보
Ruby를 사용하여 GitHub REST API와 상호 작용하는 스크립트를 작성하려면 GitHub에서 Octokit.rb SDK를 사용하는 것이 좋습니다. Octokit.rb는 GitHub에 의해 유지됨니다. SDK는 모범 사례를 구현하고 Ruby를 통해 REST API와 보다 쉽게 상호 작용할 수 있도록 합니다. Octokit.rb는 모든 최신 브라우저, Node.rb 및 Deno에서 작동합니다. Octokit.rb에 대한 자세한 정보는 Octokit.rb 추가 정보를 참조하세요.
필수 조건
이 가이드에서는 Ruby 및 GitHub REST API에 익숙하다고 가정합니다. REST API에 대한 자세한 내용은 “REST API 시작”를 참조하세요.
참고: Octokit.rb 라이브러리를 사용하려면 octokit
보석을 설치하고 가져와야 합니다. 이 가이드에서는 Ruby의 규칙에 따라 import 문을 사용합니다. 다른 설치 방법에 대한 자세한 내용은 Octokit.rb README의 설치 섹션을 참조하세요.
인스턴스화 및 인증
경고: 인증 자격 증명을 암호처럼 처리합니다.
자격 증명을 안전하게 유지하기 위해 비밀로 저장하고 GitHub Actions를 통해 스크립트를 실행할 수 있습니다. 자세한 내용은 "GitHub Actions에서 비밀 사용"을(를) 참조하세요.
이(가) 불가능하며, 다른 CLI 서비스를 사용하여 자격 증명을 안전하게 저장하는 것이 좋습니다.
personal access token을(를) 사용하여 인증
개인용으로 GitHub REST API를 사용하려는 경우 personal access token를 만들 수 있습니다. personal access token을(를) 만드는 방법에 대한 자세한 내용은 "개인용 액세스 토큰 관리"을 참조하세요.
먼저 octokit
라이브러리가 필요합니다. 그런 다음 personal access token을(를) access_token
옵션으로 전달하여 Octokit
인스턴스를 만듭니다. 다음 예제에서는 YOUR-TOKEN
을(를) personal access token으로 바꿉니다.
require 'octokit' octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')
require 'octokit'
octokit = Octokit::Client.new(access_token: 'YOUR-TOKEN')
GitHub App(으)로 인증
조직 또는 다른 사용자를 대신하여 API를 사용하려는 경우 GitHub에서 GitHub App을(를) 사용하는 것이 좋습니다. GitHub Apps에 엔드포인트를 사용할 수 있는 경우 해당 엔드포인트에 대한 REST 참조 설명서에 필요한 GitHub App 토큰 유형이 표시됩니다. 자세한 내용은 "GitHub 앱 등록" 및 "GitHub 앱을 사용한 인증 정보"을(를) 참조하세요.
octokit
이(가) 필요한 대신 GitHub App의 정보를 옵션으로 전달하여 Octokit::Client
인스턴스를 만듭니다. 다음 예제에서는 APP_ID
을(를) 앱의 ID로, PRIVATE_KEY
을(를) 앱의 프라이빗 키로, 그리고 INSTALLATION_ID
을(를) 대신 인증하려는 앱 설치의 ID로 바꿉니다. 앱 ID를 찾고 앱의 설정 페이지 설정에서 프라이빗 키를 생성할 수 있습니다. 자세한 내용은 "GitHub 앱에 대한 프라이빗 키 관리"을(를) 참조하세요. GET /users/{username}/installation
, GET /repos/{owner}/{repo}/installation
, GET /orgs/{org}/installation
엔드포인트를 사용하여 설치 ID를 가져올 수 있습니다. 자세한 내용은 "GitHub Apps에 대한 REST API 엔드포인트" 항목을 참조하세요. HOSTNAME
을(를) GitHub Enterprise Server 인스턴스의 이름으로 바꿉니다.
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)
GitHub Actions으로 인증
GitHub Actions 워크플로에서 API를 사용하려면 GitHub에서 토큰을 만드는 대신 기본 제공 GITHUB_TOKEN
으로 인증하는 것이 좋습니다. permissions
키를 사용하여 GITHUB_TOKEN
에 대한 사용 권한을 부여할 수 있습니다. GITHUB_TOKEN
에 대한 자세한 정보는 "자동 토큰 인증"을(를) 참조하세요.
워크플로가 워크플로 리포지토리 외부의 리소스에 액세스해야 하는 경우 GITHUB_TOKEN
을 사용할 수 없습니다. 이 경우 자격 증명을 비밀로 저장하고 아래 예제의 GITHUB_TOKEN
을 비밀의 이름으로 바꿉니다. 비밀에 대한 자세한 정보는 "GitHub Actions에서 비밀 사용"을(를) 참조하세요.
또한 run
키워드를 사용하여GitHub Actions 워크플로에서 Ruby 스크립트를 실행할 수 있으며 GITHUB_TOKEN
의 값을 환경 변수로 저장할 수 있습니다. 스크립트는 환경 변수에 ENV['VARIABLE_NAME']
로 액세스할 수 있습니다.
예를 들어 이 워크플로 단계에서 TOKEN
이라는 환경 변수에 GITHUB_TOKEN
을 저장합니다.
- name: Run script
env:
TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ruby .github/actions-scripts/use-the-api.rb
워크플로가 실행하는 스크립트는 ENV['TOKEN']
을 인증하는 데 사용합니다.
require 'octokit' octokit = Octokit::Client.new(access_token: ENV['TOKEN'])
require 'octokit'
octokit = Octokit::Client.new(access_token: ENV['TOKEN'])
인증 없는 인스턴스화
트래픽률 제한이 낮고 일부 엔드포인트를 사용할 수 없어도 인증 없이 REST API를 사용할 수 있습니다. 인증하지 않고 인스턴스 Octokit
을(를) 만들려면 access_token
옵션을 전달하지 마세요.
require 'octokit' octokit = Octokit::Client.new
require 'octokit'
octokit = Octokit::Client.new
요청 수행
Octokit은 요청을 만드는 여러 가지 방법을 지원합니다. 엔드포인트에 대한 HTTP 동사와 경로를 알고 있는 경우 request
메서드를 사용하여 요청을 수행할 수 있습니다. IDE에서 자동 완성 및 입력을 이용하려는 경우 rest
메서드를 사용할 수 있습니다. 페이지를 매긴 엔드포인트의 경우 paginate
메서드를 사용하여 여러 데이터 페이지를 요청할 수 있습니다.
request
메서드를 사용하여 요청을 수행합니다.
request
메서드를 사용하여 요청을 만들려면 HTTP 메서드와 경로를 첫 번째 인수로 전달합니다. 해시의 본문, 쿼리, 경로 매개 변수를 두 번째 인수로 패스합니다. 예를 들어 /repos/{owner}/{repo}/issues
에 GET
을 요청하고 owner
, repo
, 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)
request
메서드는 자동으로 Accept: application/vnd.github+json
머리글을 전달합니다. 추가 헤더 또는 다른 Accept
헤더를 전달하려면 두 번째 인수로 전달되는 해시에 headers
옵션을 추가합니다. headers
옵션의 값은 헤더 이름을 키로, 헤더 값을 값으로 가지고 있는 해시입니다. 예를 들어 text/plain
의 값과 함께 content-type
헤더를 보내려면 다음을 수행합니다.
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" })
rest
엔드포인트 메서드를 사용하여 요청
모든 REST API 엔드포인트에는 Octokit에 연결된 rest
엔드포인트 메서드가 있습니다. 이러한 메서드는 일반적으로 편의를 위해 IDE에서 자동 완성됩니다. 모든 매개 변수를 해시로 메서드에 전달할 수 있습니다.
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)
페이지 매긴 요청 만들기
엔드포인트의 페이지가 매겨지고 둘 이상의 결과 페이지를 페치하려는 경우 paginate
메서드를 사용할 수 있습니다. paginate
는 마지막 페이지에 도달할 때까지 결과의 다음 페이지를 가져온 다음 모든 결과를 배열로 반환합니다. 페이지가 매겨진 결과를 배열로 반환하는 것과는 달리 몇 개의 엔드포인트는 페이지를 매긴 결과를 개체의 배열로 반환합니다. 원시 결과가 개체인 경우에도 paginate
는 항상 항목 배열을 반환합니다.
예를 들어 다음 예제에서는 github/docs
리포지토리에서 모든 이슈를 가져옵니다. 한 번에 100개의 이슈를 요청하지만 함수는 데이터의 마지막 페이지에 도달할 때까지 반환되지 않습니다.
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)
이 paginate
메서드는 결과의 각 페이지를 처리하는 데 사용할 수 있는 선택적 블록을 허용합니다. 이렇게 하면 응답에서 원하는 데이터만 수집할 수 있습니다. 예를 들어 다음 예제에서는 제목에 "test"가 포함된 이슈가 반환될 때까지 결과를 계속 가져옵니다. 반환된 데이터 페이지의 경우 이슈 제목과 작성자만 저장됩니다.
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
모든 결과를 한 번에 가져오는 대신 한 번에 단일 페이지를 반복하는 데 octokit.paginate.iterator()
를 사용할 수 있습니다. 예를 들어 다음 예제에서는 결과의 한 페이지를 한 번에 가져오고 다음 페이지를 가져오기 전에 페이지에서 각 개체를 처리합니다. 제목에 "test"가 포함된 이슈에 도달하면 스크립트는 반복을 중지하고 처리된 각 개체의 이슈 제목 및 이슈 작성자를 반환합니다. 반복기는 페이지를 매긴 데이터를 가져오기 위한 가장 메모리 효율적인 메서드입니다.
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
rest
엔드포인트 메서드에서도 paginate
메서드를 사용할 수 있습니다. rest
엔드포인트 메서드를 첫 번째 인수로 전달하고 매개 변수를 두 번째 인수로 전달합니다.
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)
페이지 매김에 대한 자세한 정보는 “REST API에서 페이지 매김 사용”을(를) 참조하세요.
오류 포착하기
모든 오류 포착하기
경우에 따라 GitHub REST API에서 오류를 반환합니다. 예를 들어 액세스 토큰이 만료되었거나 필수 매개 변수를 생략하면 오류가 발생합니다. Octokit.rb는 400 Bad Request
, 401 Unauthorized
, 403 Forbidden
, 404 Not Found
및 422 Unprocessable Entity
이외의 오류가 발생하면 요청을 자동으로 다시 시도합니다. 재시도 후에도 API 오류가 발생하면 Octokit.rb는 응답(response.status
) 및 응답 헤더(response.headers
)의 HTTP 상태 코드를 포함하는 오류를 throw합니다. 코드에서 이러한 오류를 처리해야 합니다. 예를 들어 try/catch 블록을 사용하여 오류를 포착할 수 있습니다.
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
의도한 오류 코드 처리하기
경우에 따라 GitHub은(는) 4xx 상태 코드를 사용하여 오류가 아닌 응답을 나타냅니다. 사용 중인 엔드포인트에서 이 작업을 수행하는 경우, 특정 오류에 대한 처리를 추가할 수 있습니다. 예를 들어 GET /user/starred/{owner}/{repo}
엔드포인트는 리포지토리에 별표를 하지 않은 경우 404
를 반환합니다. 다음 예제에서는 404
응답을 사용하여 리포지토리가 별표 표시되지 않았음을 나타내고 다른 모든 오류 코드는 오류로 처리됩니다.
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
트래픽률 제한 오류 처리
트래픽률 제한 오류가 표시되는 경우 대기 후 요청을 다시 시도할 수 있습니다. 트래픽률이 제한되면 GitHub이(가) 403 Forbidden
오류로 응답하고 x-ratelimit-remaining
응답 헤더 값이 "0"
이 됩니다. 응답 헤더에는 현재 트래픽률 제한 창이 재설정되는 시간을 UTC Epoch 초 단위로 알려주는 x-ratelimit-reset
헤더가 포함됩니다. 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)
응답 사용
request
메서드는 요청이 성공한 경우 응답 개체를 반환합니다. 응답 개체는 data
(엔드포인트에서 반환된 응답 본문), status
(HTTP 응답 코드), url
(요청의 URL) 및 headers
(응답 머리글을 포함하는 해시)입니다. 달리 지정하지 않는 한 응답 본문은 JSON 형식입니다. 일부 엔드포인트는 응답 본문을 반환하지 않습니다. 이 경우, data
속성은 생략됩니다.
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']}"
마찬가지로, paginate
메서드는 응답 개체를 반환합니다. request
이(가) 성공한 경우, response
개체에는 데이터, 상태, URL 및 헤더가 포함됩니다.
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']}"
예제 스크립트
다음은 Octokit.rb를 사용하는 전체 예제 스크립트입니다. 스크립트는 Octokit
를 가져오고 새 인스턴스 Octokit
를 만듭니다. personal access token 대신 GitHub App을(를) 사용하여 인증하려는 경우 Octokit
대신 App
을 가져오고 인스턴스화합니다. 자세한 정보는 이 가이드의 “GitHub App에서 인증”을 참조하세요.
get_changed_files
함수는 끌어오기 요청에 대해 변경된 모든 파일을 가져옵니다. comment_if_data_files_changed
함수는 get_changed_files
함수를 호출합니다. 끌어오기 요청이 변경된 파일이 파일 경로에 /data/
가 포함된 경우 함수는 끌어오기 요청에 대해 설명을 달게 됩니다.
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}"
참고: 이것은 단지 기본적인 예일 뿐입니다. 실제로 오류 처리 및 조건부 검사를 사용하여 다양한 시나리오를 처리할 수 있습니다.
다음 단계
GitHub REST API 및 Octokit.rb 작업에 대해 자세히 알아보려면 다음 리소스를 살펴보세요.
- Octokit.rb에 대한 자세한 내용은 Octokit.rb 설명서를 참조하세요.
- 요청 및 응답 구조를 포함하여 GitHub의 사용 가능한 REST API 엔드포인트에 대한 자세한 내용은 GitHub REST API 설명서을 참조하세요.