# 腳本 GitHub
所以現在我們已經介紹了 GitHub 的大部分功能與工作流程,但是任意一個小組或項目都會去自定義,因為他們想要創造或擴展想要整合的服務。
對我們來說很幸運的是,GitHub 在許多方面都真的很方便 Hack。 在本節中我們將會介紹如何使用 GitHub 鉤子系統與 API 接口,使 GitHub 按照我們的設想來工作。
## 鉤子
GitHub 倉庫管理中的鉤子與服務區塊是 GitHub 與外部系統交互最簡單的方式。
### 服務
首先我們來看一下服務。 鉤子與服務整合都可以在倉庫的設置區塊中找到,就在我們之前添加協作者與改變項目的默認分支的地方。 在 “Webhooks and Services” 標簽下你會看到與?[Figure?6-49](http://git-scm.com/book/zh/v2/ch00/_services_hooks)類似的內容。

Figure 6-49.?服務與鉤子配置區域
有許多可以選擇的服務,大多數是整合到其他的商業與開源系統中。 它們中的大多數是為了整合持續集成服務、BUG 與問題追蹤系統、聊天室系統與文檔系統。 我們將會通過設置一個非常簡單的例子來介紹。 如果從 “Add Service” 選擇 “email”,會得到一個類似?[Figure?6-50](http://git-scm.com/book/zh/v2/ch00/_service_config)?的配置屏幕。

Figure 6-50.?電子郵件服務配置
在本例中,如果我們點擊 “Add service” 按鈕,每次有人推送內容到倉庫時,指定的電子郵件地址都會收到一封郵件。 服務可以監聽許多不同類型的事件,但是大多數只監聽推送事件然后使用那些數據做一些事情。
如果有一個正在使用的系統想要整合到 GitHub,應當先檢查這里看有沒有已有的可用的服務整合。 例如,如果正使用 Jenkins 來測試你的代碼庫,當每次有人推送到你的倉庫時你可以啟用 Jenkins 內置的整合啟動測試運行。
### 鉤子
如果需要做一些更具體的事,或者想要整合一個不在這個列表中的服務或站點,可以轉而使用更通用的鉤子系統。 GitHub 倉庫鉤子是非常簡單的。 指定一個 URL 然后 GitHub 在任一期望的事件發生時就會發送一個 HTTP 請求到那個 URL 。
通常做這件事的方式是可以設置一個小的 web 服務來監聽 GitHub 鉤子請求然后使用收到的數據做一些事情。
為了啟用一個鉤子,點擊?[Figure?6-49](http://git-scm.com/book/zh/v2/ch00/_services_hooks)?中的 “Add webhook” 按鈕。 這會將你引導至一個類似[Figure?6-51](http://git-scm.com/book/zh/v2/ch00/_web_hook)?的頁面。

Figure 6-51.?Web 鉤子配置
Web 鉤子的設置非常簡單。 大多數情況下只需要輸入一個 URL 與一個密鑰然后點擊 “Add webhook”。 有幾個選項可以指定在哪個事件時想要 GitHub 發送請求?—?默認的行為是只有當某人推送新代碼到倉庫的任一分支時的?`push`?事件獲得一個請求。
讓我們看一個設置處理 web 鉤子的 web 服務的小例子。 我們將會使用 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 請求然后查找推送者,他們推送到了什么分支以及推送的所有提交都改動了哪些文件。 然后我們檢查它是否與我們的條件區配,如果匹配則發送一封郵件。
為了開發與測試類似這樣的東西,在設置鉤子的地方有一個漂亮的開發者控制臺。 可以看到 GitHub 為那個 webhook 的最后幾次請求。 對每一個鉤子,當它發送后都可以深入挖掘,檢測它是否是成功的與請求及回應的消息頭與消息體。 這使得測試與調試鉤子非常容易。

Figure 6-52.?Web 鉤子調試信息
開發者控制臺的另一個很棒的功能是可以輕松地重新發送任何請求來測試你的服務。
關于如何編寫 web 鉤子與所有可監聽的不同事件類型的更多信息,請訪問在[*https://developer.github.com/webhooks/*](https://developer.github.com/webhooks/)?的 GitHub 開發者文檔。
## GitHub API
服務與鉤子給你提供了一種方式來接收關于在倉庫中發生的事件的推送通知,但是如何獲取相關事件的詳情呢?如何自動化一些諸如添加協作者或給問題加標簽的事情呢?
這是 GitHub API 派上用場的地方。 在自動化流行的趨勢下,GitHub 提供了大量的 API 接口,可以進行幾乎任何能在網站上進行的操作。 在本節中我們將會學習如何授權與連接到 API,如何通過 API 在一個問題上評論與如何修改一個 Pull Request 的狀態。
### 基本用途
可以做的最基本的事情是向一個不需要授權的接口上發送一個簡單的 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 http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}
~~~
### 在一個問題上評論
然而,如果想要在網站上進行一個操作,如在 Issue 或 Pull Request 上評論,或者想要查看私有內容或與其交互,你需要授權。
這里提供了幾種授權方式。 你可以使用僅需用戶名與密碼的基本授權,但是通常更好的主意是使用一個個人訪問令牌。 可以從設置頁的 “Applications” 標簽生成訪問令牌。

Figure 6-53.?從設置頁的 “Applications” 標簽生成訪問令牌。
它會詢問這個令牌的作用域與一個描述。 確保使用一個好的描述信息,這樣當腳本或應用不再使用時你會很放心地移除。
GitHub 只會顯示令牌一次,所以記得一定要拷貝它。 現在可以在腳本中使用它代替使用用戶名寫密碼來授權。 這很漂亮,因為可以限制想要做的范圍并且令牌是可廢除的。
這也會有一個提高頻率上限的附加優點。 如果沒有授權的話,你會被限制在一小時最多發起 60 次請求。 如果授權則可以一小時最多發起 5000 次請求。
所以讓我們利用它來對我們的其中一個問題進行評論。 想要對一個特定問題 Issue #6 留下一條評論。 必須使用剛剛生成的令牌作為 Authorization 頭信息,發送一個到`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:"
}
~~~
現在如果進入到那個問題,可以看到我們剛剛發布的評論,像?[Figure?6-54](http://git-scm.com/book/zh/v2/ch00/_api_comment)?一樣。

Figure 6-54.?從 GitHub API 發布的一條評論
可以使用 API 去做任何可以在網站上做的事情?—?創建與設置里程碑、指派人員到 Issues 與 Pull Requests,創建與修改標簽、訪問提交數據、創建新的提交與分支、打開關閉或合并 Pull Requests、創建與編輯團隊、在 Pull Request 中評論某行代碼、搜索網站等等。
## 修改 Pull Request 的狀態
如果使用 Pull Requests 的話我們將要看到的最后一個例子會很有用。 每一個提交可以有一個或多個與它關聯的狀態,有 API 來添加與查詢狀態。
大多數持續集成與測試服務通過測試推送的代碼后使用這個 API 來回應,然后報告提交是否通過了全部測試。 你也可以使用該接口來檢查提交信息是否經過合適的格式化、提交者是否遵循了所有你的貢獻準則、提交是否經過有效的簽名?—?種種這類事情。
假設在倉庫中設置了一個 web 鉤子訪問一個用來檢查提交信息中的?`Signed-off-by`?字符串的小的 web 服務。
~~~
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 鉤子處理器中我們瀏覽剛剛推送上來的每一個提交,在提交信息中查找字符串?*Signed-off-by*?并且最終使用 HTTP 向`/repos/<user>/<repo>/statuses/<commit_sha>`?API 接口發送一個帶有狀態的 POST 請求。
在本例中可以發送一個狀態(*success*,?*failure*,?*error*)、一個發生了什么的描述信息、一個用戶可以了解更多信息的目標 URL 與一個 “context” 以防一個單獨的提交有多個狀態。 例如,一個測試服務可以提供一個狀態與一個類似這樣的驗證服務也可能提供一個狀態?—?“context” 字段是用來區別它們的。
如果某人在 GitHub 中打開了一個新的 Pull Request 并且這個鉤子已經設置,會看到類似[Figure?6-55](http://git-scm.com/book/zh/v2/ch00/_commit_status)?的信息。

Figure 6-55.?通過 API 的提交狀態
現在可以看到一個小的綠色對勾標記在提交信息中有 “Signed-off-by” 的提交旁邊,紅色的對勾標記在作者忘記簽名的提交旁邊。 也可以看到 Pull Request 顯示在那個分支上的最后提交的狀態,如果失敗的話會警告你。 如果對測試結果使用這個 API 那么就不會不小心合并某些未通過測試的最新提交。
### Octokit
盡管我們在這些例子中都是通過?`curl`?與基本的 HTTP 請求來做幾乎所有的事情,還有一些以更自然的方式利用 API 的開源庫存在著。 在寫這篇文章的時候,被支持的語言包括 Go、Objective-C、Ruby 與 .NET。 訪問?[*http://github.com/octokit*](http://github.com/octokit)?了解更多相關信息,它們幫你處理了更多 HTTP 相關的內容。
希望這些工具能幫助你自定義與修改 GitHub 來更好地為特定的工作流程工作。 關于全部 API 的完整文檔與常見任務的指南,請查閱?[*https://developer.github.com*](https://developer.github.com/)。
- 前言
- Scott Chacon 序
- Ben Straub 序
- 獻辭
- 貢獻者
- 引言
- 1. 起步
- 1.1 關于版本控制
- 1.2 Git 簡史
- 1.3 Git 基礎
- 1.4 命令行
- 1.5 安裝 Git
- 1.6 初次運行 Git 前的配置
- 1.7 獲取幫助
- 1.8 總結
- 2. Git 基礎
- 2.1 獲取 Git 倉庫
- 2.2 記錄每次更新到倉庫
- 2.3 查看提交歷史
- 2.4 撤消操作
- 2.5 遠程倉庫的使用
- 2.6 打標簽
- 2.7 Git 別名
- 2.8 總結
- 3. Git 分支
- 3.1 分支簡介
- 3.2 分支的新建與合并
- 3.3 分支管理
- 3.4 分支開發工作流
- 3.5 遠程分支
- 3.6 變基
- 3.7 總結
- 4. 服務器上的 Git
- 4.1 協議
- 4.2 在服務器上搭建 Git
- 4.3 生成 SSH 公鑰
- 4.4 配置服務器
- 4.5 Git 守護進程
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 第三方托管的選擇
- 4.10 總結
- 5. 分布式 Git
- 5.1 分布式工作流程
- 5.2 向一個項目貢獻
- 5.3 維護項目
- 5.4 總結
- 6. GitHub
- 6.1 賬戶的創建和配置
- 6.2 對項目做出貢獻
- 6.3 維護項目
- 6.4 管理組織
- 6.5 腳本 GitHub
- 6.6 總結
- 7. Git 工具
- 7.1 選擇修訂版本
- 7.2 交互式暫存
- 7.3 儲藏與清理
- 7.4 簽署工作
- 7.5 搜索
- 7.6 重寫歷史
- 7.7 重置揭密
- 7.8 高級合并
- 7.9 Rerere
- 7.10 使用 Git 調試
- 7.11 子模塊
- 7.12 打包
- 7.13 替換
- 7.14 憑證存儲
- 7.15 總結
- 8. 自定義 Git
- 8.1 配置 Git
- 8.2 Git 屬性
- 8.3 Git 鉤子
- 8.4 使用強制策略的一個例子
- 8.5 總結
- 9. Git 與其他系統
- 9.1 作為客戶端的 Git
- 9.2 遷移到 Git
- 9.3 總結
- 10. Git 內部原理
- 10.1 底層命令和高層命令
- 10.2 Git 對象
- 10.3 Git 引用
- 10.4 包文件
- 10.5 引用規格
- 10.6 傳輸協議
- 10.7 維護與數據恢復
- 10.8 環境變量
- 10.9 總結
- A. 其它環境中的 Git
- A1.1 圖形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Eclipse 中的 Git
- A1.4 Bash 中的 Git
- A1.5 Zsh 中的 Git
- A1.6 Powershell 中的 Git
- A1.7 總結
- B. 將 Git 嵌入你的應用
- A2.1 命令行 Git 方式
- A2.2 Libgit2
- A2.3 JGit
- C. Git 命令
- A3.1 設置與配置
- A3.2 獲取與創建項目
- A3.3 快照基礎
- A3.4 分支與合并
- A3.5 項目分享與更新
- A3.6 檢查與比較
- A3.7 調試
- A3.8 補丁
- A3.9 郵件
- A3.10 外部系統
- A3.11 管理
- A3.12 底層命令