Git
章節 ▾ 第二版

6.5 GitHub - 撰寫 GitHub 腳本

撰寫 GitHub 腳本

現在我們已經涵蓋了 GitHub 的所有主要功能和工作流程,但任何大型群組或專案都會有他們可能想要進行的自訂或他們可能想要整合的外部服務。

對我們來說幸運的是,GitHub 在許多方面都非常容易駭入。在本節中,我們將介紹如何使用 GitHub 掛鉤系統及其 API,使 GitHub 按照我們想要的方式工作。

服務和掛鉤

GitHub 儲存庫管理中的「掛鉤和服務」部分是讓 GitHub 與外部系統互動的最簡單方法。

服務

首先,我們將看看服務。「掛鉤」和「服務」整合都可以在您的儲存庫的「設定」區段中找到,我們先前在這裡查看了新增「協作者」和變更專案的預設分支。在「Webhooks 和服務」標籤下,您會看到類似 服務和掛鉤組態區段的內容。

Services and Hooks configuration section
圖 129. 服務和掛鉤組態區段

您可以從數十種服務中進行選擇,其中大多數是與其他商業和開放原始碼系統的整合。它們大多數用於持續整合服務、錯誤和問題追蹤器、聊天室系統和文件系統。我們將逐步說明如何設定一個非常簡單的服務:「電子郵件」掛鉤。如果您從「新增服務」下拉式選單中選擇「電子郵件」,您將會看到類似 電子郵件服務組態的組態畫面。

Email service configuration
圖 130. 電子郵件服務組態

在這種情況下,如果我們按下「新增服務」按鈕,我們指定的電子郵件地址會在每次有人推送至儲存庫時收到一封電子郵件。服務可以監聽許多不同類型的事件,但大多數只監聽推送事件,然後使用該資料執行某些操作。

如果您正在使用想要與 GitHub 整合的系統,您應該在此處檢查是否有現有的服務整合可用。例如,如果您使用 Jenkins 在您的程式碼庫上執行測試,您可以啟用 Jenkins 內建服務整合,以便在每次有人推送至您的儲存庫時啟動測試執行。

掛鉤

如果您需要更具體的內容,或者您想要與此清單中未包含的服務或網站整合,您可以改為使用更通用的「掛鉤」系統。GitHub 儲存庫掛鉤非常簡單。您指定一個 URL,GitHub 會在您想要的任何事件發生時將 HTTP 酬載發佈到該 URL。

一般而言,其運作方式是您可以設定一個小型 Web 服務來監聽 GitHub 掛鉤酬載,然後在收到資料時使用該資料執行某些操作。

若要啟用 Hook,請點擊「服務與 Hook」設定區塊中的「新增 webhook」按鈕,這個按鈕會將您帶到一個看起來像「Web hook 設定」的頁面。

Web hook configuration
圖 131. Web hook 設定

Web hook 的設定相當簡單。在大多數情況下,您只需輸入 URL 和密鑰,然後點擊「新增 webhook」即可。您還可以選擇要讓 GitHub 針對哪些事件傳送酬載,預設值是僅在有人將新程式碼推送至您的儲存庫的任何分支時,才接收 push 事件的酬載。

讓我們來看一個小型範例,了解如何設定 Web 服務來處理 Web hook。我們將使用 Ruby Web 框架 Sinatra,因為它相當簡潔,您應該可以輕鬆了解我們正在做什麼。

假設我們希望在特定人士將變更特定檔案的程式碼推送到我們專案的特定分支時收到電子郵件。我們可以透過類似以下的程式碼輕鬆完成此操作:

require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end

在這裡,我們接收 GitHub 傳送給我們的 JSON 酬載,並查找推送者、他們推送到的分支,以及所有已推送的提交中修改的檔案。然後,我們會根據我們的條件檢查,並在符合條件時傳送電子郵件。

為了開發和測試類似這樣的內容,您可以在設定 hook 的同一個畫面上找到一個方便的開發人員主控台。您可以查看 GitHub 嘗試為該 Webhook 執行的最後幾次傳遞。對於每個 hook,您可以深入查看它在何時傳遞、是否成功,以及請求和回應的本文和標頭。這讓測試和偵錯您的 hook 變得非常容易。

Web hook debugging information
圖 132. Web hook 偵錯資訊

這個功能的另一個優點是,您可以輕鬆地重新傳遞任何酬載來測試您的服務。

如需更多關於如何撰寫 Webhook 以及您可以監聽的所有不同事件類型的資訊,請前往 GitHub 開發人員文件:https://docs.github.com/en/webhooks-and-events/webhooks/about-webhooks

GitHub API

服務和 Hook 提供了一種接收有關您的儲存庫上發生的事件的推播通知的方式,但如果您需要更多關於這些事件的資訊該怎麼辦?如果您需要自動執行像是新增協作者或標籤議題之類的操作該怎麼辦?

這就是 GitHub API 派上用場的地方。GitHub 有大量的 API 端點,幾乎可以自動完成您在網站上可以做的任何事情。在本節中,我們將學習如何驗證並連線到 API、如何對議題發表評論,以及如何透過 API 變更提取請求的狀態。

基本用法

您可以做的最基本的事情是對不需要驗證的端點進行簡單的 GET 請求。這可能是使用者或開放原始碼專案上的唯讀資訊。例如,如果我們想知道更多關於名為「schacon」的使用者的資訊,我們可以執行類似以下的指令:

$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}

有許多類似這樣的端點可以獲取有關組織、專案、議題、提交的資訊,幾乎涵蓋您可以在 GitHub 上公開看到的所有內容。您甚至可以使用 API 來轉譯任意 Markdown 或尋找 .gitignore 範本。

$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}

評論議題

但是,如果您想要在網站上執行像是評論議題或提取請求之類的操作,或者如果您想要檢視或與私有內容互動,則需要進行驗證。

有多種驗證方式。您可以使用基本驗證,僅使用您的使用者名稱和密碼,但通常使用個人存取權杖是更好的選擇。您可以從設定頁面的「應用程式」索引標籤產生此權杖。

Generate your access token from the “Applications” tab of your settings page
圖 133. 從設定頁面的「應用程式」索引標籤產生您的存取權杖

它會詢問您此權杖想要使用的範圍和描述。請務必使用良好的描述,以便在您的腳本或應用程式不再使用時,您可以放心移除該權杖。

GitHub 只會顯示一次權杖,因此請務必複製它。您現在可以在腳本中使用它進行驗證,而無需使用使用者名稱和密碼。這樣做的好處是您可以限制您想要執行的操作範圍,而且權杖是可以撤銷的。

這也帶來了增加速率限制的額外優點。在不驗證的情況下,您每小時將被限制為 60 個請求。如果驗證通過,您每小時可以發出最多 5,000 個請求。

因此,讓我們用它在我們的其中一個議題上發表評論。假設我們想要在特定議題(議題 #6)上發表評論。為此,我們必須向 repos/<user>/<repo>/issues/<num>/comments 發出 HTTP POST 請求,並將我們剛產生的權杖作為授權標頭。

$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}

現在,如果您前往該議題,您會看到我們剛剛成功發布的評論,如「GitHub API 發布的評論」所示。

A comment posted from the GitHub API
圖 134. GitHub API 發布的評論

您可以使用 API 來執行您可以在網站上做的任何事情,例如建立和設定里程碑、將人員指派給議題和提取請求、建立和變更標籤、存取提交資料、建立新的提交和分支、開啟、關閉或合併提取請求、建立和編輯團隊、評論提取請求中的程式碼行、搜尋網站等等。

變更提取請求的狀態

我們將看的最後一個範例非常有用,因為如果您正在使用提取請求,它會非常有用。每個提交都可以有一個或多個與之相關聯的狀態,並且有一個 API 可以新增和查詢該狀態。

大多數持續整合和測試服務都會使用此 API 來回應推送,方法是測試推送的程式碼,然後回報該提交是否已通過所有測試。您也可以使用它來檢查提交訊息的格式是否正確、提交者是否遵循您的所有貢獻指南、提交是否已正確簽署,以及其他任何事情。

假設您在您的儲存庫上設定了一個 webhook,它會連到一個小型 Web 服務,該服務會檢查提交訊息中是否有 Signed-off-by 字串。

require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # look through each commit message
  push["commits"].each do |commit|

    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end

希望這很容易理解。在這個 Web hook 處理常式中,我們會檢查剛推送的每個提交、在提交訊息中尋找字串「Signed-off-by」,最後透過 HTTP 將狀態 POST 到 /repos/<user>/<repo>/statuses/<commit_sha> API 端點。

在這種情況下,您可以傳送狀態(「success」、「failure」、「error」)、事件的描述、使用者可以前往以取得更多資訊的目標 URL,以及「內容」,以防單一提交有多個狀態。例如,測試服務可能會提供一個狀態,而像這樣的驗證服務也可能會提供一個狀態,「內容」欄位是它們的區別方式。

如果有人在 GitHub 上開啟新的提取請求,並且設定了這個 hook,您可能會看到類似「透過 API 提交狀態」的內容。

Commit status via the API
圖 135. 透過 API 提交狀態

您現在可以在訊息中具有「Signed-off-by」字串的提交旁邊看到一個小綠色勾號,並在作者忘記簽署的提交旁邊看到一個紅色叉號。您也可以看到提取請求會採用分支上最後一次提交的狀態,並在失敗時警告您。如果您將此 API 用於測試結果,這會非常有用,這樣您就不會不小心合併最後一次提交失敗的內容。

Octokit

雖然我們在這些範例中幾乎都是透過 curl 和簡單的 HTTP 請求來完成所有操作,但已經存在幾個開放原始碼程式庫,可以更慣用的方式使用此 API。在撰寫本文時,支援的語言包括 Go、Objective-C、Ruby 和 .NET。查看 https://github.com/octokit 以取得更多關於這些程式庫的資訊,因為它們為您處理了大部分的 HTTP 作業。

希望這些工具可以協助您自訂和修改 GitHub,使其更適合您的特定工作流程。如需關於整個 API 的完整文件以及常見任務的指南,請查看 https://docs.github.com/

scroll-to-top