اکنون که تمام ویژگیها و جریانهای کاری اصلی گیتهاب را بررسی کردیم، اما هر گروه یا پروژه بزرگی ممکن است بخواهد سفارشیسازیهایی انجام دهد یا سرویسهای خارجی را به گیتهاب متصل کند.
خوشبختانه، گیتهاب به روشهای زیادی قابل هک و سفارشیسازی است. در این بخش، نحوه استفاده از سیستم hooks و API گیتهاب را بررسی میکنیم تا گیتهاب را مطابق نیاز خودمان تنظیم کنیم.
بخش Hooks و Services در مدیریت مخزن گیتهاب سادهترین راه برای تعامل گیتهاب با سیستمهای خارجی است.
ابتدا نگاهی به سرویسها میاندازیم. هر دو نوع یکپارچهسازی Hooks و Services در بخش تنظیمات مخزن شما قابل دسترسی هستند، جایی که قبلاً درباره اضافه کردن همکاران و تغییر شاخه پیشفرض پروژه صحبت کردیم. در تب «Webhooks and Services» چیزی شبیه Services and Hooks configuration section. مشاهده خواهید کرد.
دهها سرویس مختلف وجود دارد که میتوانید از بین آنها انتخاب کنید، که بیشتر آنها یکپارچهسازی با سیستمهای تجاری و متنباز دیگر هستند. اکثر این سرویسها برای خدمات یکپارچهسازی پیوسته (Continuous Integration)، پیگیری باگ و مسائل (bug and issue trackers)، سیستمهای چت و سیستمهای مستندسازی استفاده میشوند. ما مراحل راهاندازی یک سرویس بسیار ساده را مرور میکنیم: هوک ایمیل (Email hook). اگر از منوی کشویی «Add Service»، گزینه «email» را انتخاب کنید، صفحه تنظیماتی مشابه Email service configuration. برای شما نمایش داده میشود.
در این حالت، اگر روی دکمه «Add service» کلیک کنیم، آدرس ایمیلی که مشخص کردهایم، هر بار که کسی به مخزن push انجام دهد، یک ایمیل دریافت خواهد کرد. سرویسها میتوانند به انواع مختلفی از رویدادها گوش دهند، اما بیشتر آنها فقط به رویدادهای push گوش میدهند و سپس با آن داده کاری انجام میدهند.
اگر از سیستمی استفاده میکنید که میخواهید آن را با گیتهاب یکپارچه کنید، بهتر است ابتدا بررسی کنید که آیا یکپارچهسازی از پیشساختهای (Service Integration) برای آن وجود دارد یا نه. برای مثال، اگر از Jenkins برای اجرای تستهای کد استفاده میکنید، میتوانید سرویس داخلی Jenkins را فعال کنید تا هر بار که کسی به مخزن شما push انجام داد، بهطور خودکار یک اجرای تست شروع شود.
اگر به چیزی خاصتر نیاز دارید یا میخواهید با سرویس یا سایتی یکپارچهسازی انجام دهید که در لیست سرویسهای موجود نیست، میتوانید از سیستم کلیتر هوکها (Hooks) استفاده کنید. هوکهای مخزن گیتهاب بسیار ساده هستند. شما یک آدرس URL مشخص میکنید و گیتهاب در رویدادهایی که انتخاب کردهاید، یک محتوای HTTP (payload) به آن آدرس ارسال میکند.
بهطور کلی، روش کار اینگونه است که یک سرویس وب کوچک راهاندازی میکنید تا به محتوای ارسالشده از گیتهاب گوش دهد و سپس با دادهی دریافتی کاری انجام دهد.
برای فعالسازی یک هوک، روی دکمه «Add webhook» در بخش Services and Hooks configuration section. کلیک کنید. این کار شما را به صفحهای هدایت میکند که شبیه به Web hook configuration. خواهد بود.
پیکربندی یک وبهوک (web hook) نسبتاً ساده است. در اغلب موارد، فقط کافی است یک URL و یک کلید امنیتی (secret key) وارد کرده و روی «Add webhook» کلیک کنید. چند گزینه وجود دارد که مشخص میکند گیتهاب برای چه رویدادهایی باید payload ارسال کند — بهصورت پیشفرض، فقط در زمان رخداد push (یعنی زمانی که کسی کدی را به هر شاخهای از مخزن شما push میکند) payload دریافت میشود.
بیایید یک مثال کوچک از یک سرویس وب ببینیم که ممکن است برای مدیریت یک web hook تنظیم کرده باشید. ما از فریمورک Ruby به نام Sinatra استفاده میکنیم چون بسیار مختصر است و بهراحتی میتوانید متوجه شوید که چه کاری انجام میدهد.
فرض کنیم میخواهیم هر زمان که یک شخص خاص، به شاخهای خاص از پروژه کدی push کند که فایل مشخصی را تغییر داده، یک ایمیل دریافت کنیم. میتوانیم این کار را با کدی شبیه به این، نسبتاً راحت انجام دهیم:
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
در اینجا، ما محتوای JSON که گیتهاب برای ما ارسال میکند را میگیریم و بررسی میکنیم که چه کسی push انجام داده، روی کدام شاخه (branch) این کار انجام شده و چه فایلهایی در تمام commitهای ارسالشده تغییر کردهاند. سپس این اطلاعات را با معیارهایی که مشخص کردهایم مقایسه میکنیم و اگر مطابقت داشتند، یک ایمیل ارسال میکنیم.
برای توسعه و تست چنین چیزی، گیتهاب یک کنسول توسعهدهنده مفید در همان صفحهای که هوک را تنظیم کردهاید ارائه میدهد. شما میتوانید آخرین ارسالهایی (delivery) که گیتهاب برای آن وبهوک انجام داده را مشاهده کنید. برای هر هوک، میتوانید جزئیاتی مثل زمان ارسال، موفقیت یا شکست بودن آن، محتوای درخواست (Request) و پاسخ (Response) بههمراه هدرهایشان را ببینید.
این ویژگی باعث میشود تست و اشکالزدایی (debug) هوکهای شما بسیار ساده و سریع انجام شود.
ویژگی فوقالعاده دیگر این است که میتوانید هر یک از payloadهایی که قبلاً ارسال شدهاند را مجدداً ارسال (redeliver) کنید تا سرویس خود را بهراحتی تست کنید.
برای اطلاعات بیشتر درباره نحوه نوشتن webhook و انواع مختلف رویدادهایی که میتوانید به آنها گوش دهید، به مستندات توسعهدهندگان گیتهاب در این آدرس مراجعه کنید: https://developer.github.com/webhooks/
سرویسها و هوکها این امکان را به شما میدهند که نوتیفیکیشنهایی دربارهی رویدادهای رخداده در مخازنتان دریافت کنید؛ اما اگر به اطلاعات بیشتری درباره این رویدادها نیاز داشته باشید چه؟ یا اگر بخواهید کارهایی مثل افزودن همکار (collaborator) یا برچسبگذاری روی issues را بهصورت خودکار انجام دهید چه؟
اینجاست که GitHub API به کارتان میآید. گیتهاب تعداد زیادی API endpoint دارد که تقریباً هر کاری که روی وبسایت میتوانید انجام دهید را، بهشکل خودکار ممکن میسازد.
در این بخش یاد میگیریم چطور به API گیتهاب احراز هویت و اتصال برقرار کنیم، چگونه روی یک issue نظر (comment) بگذاریم و چطور وضعیت یک Pull Request را از طریق API تغییر دهیم.
پایهایترین کاری که میتوان انجام داد، یک درخواست GET ساده به یک endpoint است که نیازی به احراز هویت ندارد. این میتواند اطلاعات مربوط به یک کاربر یا دادههای فقطخواندنی (read-only) درباره یک پروژه متنباز باشد.
برای مثال، اگر بخواهیم درباره کاربری به نام 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"
}
تعداد زیادی endpoint مانند این وجود دارد که میتوانید از آنها برای دریافت اطلاعات درباره سازمانها، پروژهها، issues، commit ها و تقریباً هر چیزی که بهصورت عمومی در گیتهاب قابل مشاهده است، استفاده کنید.
حتی میتوانید با استفاده از API، محتوای Markdown دلخواه را رندر (render) کنید یا یک قالب .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*
"
}
با این حال، اگر بخواهید کاری در خود وبسایت انجام دهید — مثلاً نوشتن نظر روی یک Issue یا Pull Request — یا اگر بخواهید به محتوای خصوصی (Private) دسترسی داشته باشید یا با آن تعامل کنید، لازم است احراز هویت انجام دهید.
چندین روش برای احراز هویت وجود دارد. میتوانید از احراز هویت پایه فقط با نام کاربری و رمز عبور استفاده کنید، اما معمولاً بهتر است از یک توکن دسترسی شخصی استفاده کنید. میتوانید این توکن را از بخش «Applications» در صفحه تنظیمات خود ایجاد کنید.
از شما میپرسد که برای این توکن چه دسترسیهایی (scopes) میخواهید و یک توضیح وارد کنید. حتماً از توضیح خوبی استفاده کنید تا وقتی که دیگر نیازی به اسکریپت یا برنامهتان ندارید، بتوانید با اطمینان توکن را حذف کنید.
گیتهاب تنها یک بار این توکن را به شما نشان میدهد، پس حتماً آن را کپی کنید. حالا میتوانید از این توکن برای احراز هویت در اسکریپت خود استفاده کنید، به جای نام کاربری و رمز عبور. این روش خوب است چون میتوانید محدوده دسترسیها را محدود کنید و توکن قابلیت لغو شدن دارد.
همچنین این روش مزیت دیگری هم دارد: افزایش محدودیت درخواستها. بدون احراز هویت، محدودیت شما ۶۰ درخواست در ساعت است. اما اگر احراز هویت کنید، میتوانید تا ۵۰۰۰ درخواست در ساعت ارسال کنید.
پس بیایید از این توکن استفاده کنیم تا یک نظر روی یکی از مسئله هایمان ثبت کنیم. فرض کنیم میخواهیم یک نظر روی مسئله خاصی، یعنی مسئله شماره ۶، بگذاریم. برای این کار باید یک درخواست HTTP از نوع POST به آدرس repos/<user>/<repo>/issues/<num>/comments ارسال کنیم، که در آن به جای <user>، <repo> و <num> مقادیر مناسب قرار میگیرند، و توکنی که ساختیم را به عنوان هدر Authorization بفرستیم.
$ 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:"
}
حالا اگر به آن مسئله مراجعه کنید، میتوانید نظری که همین الان با موفقیت ثبت کردیم را ببینید، مشابه چیزی که در A comment posted from the GitHub API. نشان داده شده است.
شما میتوانید با استفاده از API تقریباً هر کاری که روی وبسایت انجام میدهید را انجام دهید — از ایجاد و تنظیم مایلستون ها، اختصاص دادن افراد به Issues و Pull Requests، ساخت و تغییر لیبل ها، دسترسی به داده های کامیت، ایجاد کامیت ها و شاخه های جدید، باز و بسته کردن یا ادغام Pull Requests، ایجاد و ویرایش تیمها، نظر دادن روی خطوط کد در یک Pull Request، جستجو در سایت و بسیاری کارهای دیگر. ==== Changing the Status of a Pull Request
یک مثال نهایی داریم که خیلی مفید است اگر با Pull Request ها کار میکنید. هر کامیت میتواند یک یا چند وضعیت (status) مرتبط با خودش داشته باشد و یک API وجود دارد که بتوانید این وضعیتها را اضافه یا بررسی کنید.
بیشتر سرویسهای تست و ادغام پیوسته (Continuous Integration) از این API استفاده میکنند تا پس از هر پوش، کد را تست کنند و نتیجه را گزارش دهند که آیا کامیت تمام تستها را گذرانده یا نه. شما هم میتوانید از این API استفاده کنید تا بررسی کنید آیا پیام کامیت به درستی فرمت شده، ارسالکننده قوانین مشارکت شما را رعایت کرده، امضای کامیت معتبر است یا نه — هر تعداد بررسی دیگر.
فرض کنید یک وبهوک (webhook) روی مخزن خود تنظیم کردهاید که به یک سرویس وب کوچک متصل میشود و در پیام کامیت به دنبال عبارت 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
امیدوارم این موضوع تا اینجا نسبتاً ساده و قابل دنبال کردن باشد. در این پردازشگر وبهوک، هر کامیتی که تازه پوش شده را بررسی میکنیم، دنبال عبارت «Signed-off-by» در پیام کامیت میگردیم و در نهایت یک درخواست HTTP از نوع POST به آدرس /repos/<user>/<repo>/statuses/<commit_sha> ارسال میکنیم تا وضعیت مربوطه را ثبت کنیم.
در این درخواست میتوانید یک حالت (state) مثل success
(موفق)، failure
(شکست) یا error
(خطا) بفرستید، همچنین توضیحی درباره آنچه اتفاق افتاده، یک URL مقصد که کاربر بتواند برای اطلاعات بیشتر به آن مراجعه کند و یک context
که وقتی چند وضعیت مختلف برای یک کامیت وجود دارد، بتوان آنها را از هم تفکیک کرد.
برای مثال، یک سرویس تست ممکن است یک وضعیت ارسال کند و یک سرویس اعتبارسنجی هم وضعیت دیگری ارائه دهد — فیلد «context» به تفکیک آنها کمک میکند.
اگر کسی یک Pull Request جدید روی گیتهاب باز کند و این وبهوک فعال باشد، ممکن است چیزی شبیه Commit status via the API. ببینید.
حالا میتوانید یک علامت کوچک تیک سبز کنار کامیتی که در پیامش عبارت «Signed-off-by» وجود دارد ببینید، و یک ضربدر قرمز روی کامیتی که نویسنده فراموش کرده امضا کند. همچنین میبینید که وضعیت Pull Request بر اساس آخرین کامیت روی شاخه تعیین میشود و اگر وضعیت آن شکست باشد، به شما هشدار میدهد. این موضوع خیلی کاربردی است اگر از این API برای نتایج تستها استفاده کنید تا به صورت تصادفی چیزی که آخرین کامیتش تستها را رد کرده، ادغام نشود.
با اینکه در این مثالها تقریباً همه چیز را با curl و درخواستهای ساده HTTP انجام دادهایم، چندین کتابخانه متن باز وجود دارد که این API را به روشی طبیعیتر و رایجتر برای زبانهای برنامه نویسی مختلف در دسترس قرار میدهند. در زمان نگارش این متن، زبانهای پشتیبانی شده شامل Go، Objective-C، Ruby و .NET هستند. برای اطلاعات بیشتر میتوانید به https://github.com/octokit مراجعه کنید؛ این کتابخانهها بخش زیادی از کارهای مربوط به HTTP را برای شما مدیریت میکنند.
امیدوارم این ابزارها به شما کمک کنند تا گیتهاب را بهتر و متناسب با جریان کاری خاص خودتان سفارشی و بهینه کنید. برای مستندات کامل API و راهنمایی در انجام کارهای رایج، به https://developer.github.com مراجعه کنید.