Skip to main content

REST API 및 Ruby를 사용하여 스크립팅

Octokit.rb SDK를 사용하여 REST API와 상호 작용하는 스크립트를 작성하는 방법을 알아봅니다.

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에서 비밀 사용"을(를) 참조하세요.

또한 토큰을 Codespaces 비밀로 저장하고 Codespaces에서 스크립트를 실행할 수도 있습니다. 자세한 정보는 "GitHub Codespaces에 대한 계정별 비밀 관리"을(를) 참조하세요.

이(가) 옵션을 사용할 수 없는 경우, 다른 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으로 바꿉니다.

Ruby
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 엔드포인트" 항목을 참조하세요.

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으로 인증

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']을 인증하는 데 사용합니다.

Ruby
require 'octokit'

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

인증 없는 인스턴스화

트래픽률 제한이 낮고 일부 엔드포인트를 사용할 수 없어도 인증 없이 REST API를 사용할 수 있습니다. 인증하지 않고 인스턴스 Octokit을(를) 만들려면 access_token 옵션을 전달하지 마세요.

Ruby
require 'octokit'

octokit = Octokit::Client.new

요청 수행

Octokit은 요청을 만드는 여러 가지 방법을 지원합니다. 엔드포인트에 대한 HTTP 동사와 경로를 알고 있는 경우 request 메서드를 사용하여 요청을 수행할 수 있습니다. IDE에서 자동 완성 및 입력을 이용하려는 경우 rest 메서드를 사용할 수 있습니다. 페이지를 매긴 엔드포인트의 경우 paginate 메서드를 사용하여 여러 데이터 페이지를 요청할 수 있습니다.

request 메서드를 사용하여 요청을 수행합니다.

request 메서드를 사용하여 요청을 만들려면 HTTP 메서드와 경로를 첫 번째 인수로 전달합니다. 해시의 본문, 쿼리, 경로 매개 변수를 두 번째 인수로 패스합니다. 예를 들어 /repos/{owner}/{repo}/issuesGET을 요청하고 owner, repo, 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 옵션의 값은 헤더 이름을 키로, 헤더 값을 값으로 가지고 있는 해시입니다. 예를 들어 text/plain의 값과 함께 content-type 헤더를 보내려면 다음을 수행합니다.

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

rest 엔드포인트 메서드를 사용하여 요청

모든 REST API 엔드포인트에는 Octokit에 연결된 rest 엔드포인트 메서드가 있습니다. 이러한 메서드는 일반적으로 편의를 위해 IDE에서 자동 완성됩니다. 모든 매개 변수를 해시로 메서드에 전달할 수 있습니다.

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

rest 엔드포인트 메서드에서도 paginate 메서드를 사용할 수 있습니다. rest 엔드포인트 메서드를 첫 번째 인수로 전달하고 매개 변수를 두 번째 인수로 전달합니다.

Ruby
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 Found422 Unprocessable Entity 이외의 오류가 발생하면 요청을 자동으로 다시 시도합니다. 재시도 후에도 API 오류가 발생하면 Octokit.rb는 응답(response.status) 및 응답 헤더(response.headers)의 HTTP 상태 코드를 포함하는 오류를 throw합니다. 코드에서 이러한 오류를 처리해야 합니다. 예를 들어 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"이 됩니다. 응답 헤더에는 현재 트래픽률 제한 창이 재설정되는 시간을 UTC Epoch 초 단위로 알려주는 x-ratelimit-reset 헤더가 포함됩니다. 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를 만듭니다. personal access token 대신 GitHub App을(를) 사용하여 인증하려는 경우 Octokit 대신 App을 가져오고 인스턴스화합니다. 자세한 정보는 이 가이드의 “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}"

참고: 이것은 단지 기본적인 예일 뿐입니다. 실제로 오류 처리 및 조건부 검사를 사용하여 다양한 시나리오를 처리할 수 있습니다.

다음 단계

GitHub REST API 및 Octokit.rb 작업에 대해 자세히 알아보려면 다음 리소스를 살펴보세요.

  • Octokit.rb에 대한 자세한 내용은 Octokit.rb 설명서를 참조하세요.
  • 요청 및 응답 구조를 포함하여 GitHub의 사용 가능한 REST API 엔드포인트에 대한 자세한 내용은 GitHub REST API 설명서을 참조하세요.