Chapters ▾ 2nd Edition

6.5 GitHub (گیت هاب) - اسکریپتنویسی در گیتهاب (Scripting GitHub)

اسکریپتنویسی در گیتهاب (Scripting GitHub)

حالا که همهٔ ویژگیها و روندهای اصلی گیتهاب را بررسی کردیم، هر گروه یا پروژهٔ بزرگی ممکن است بخواهد تغییرات سفارشی یا سرویسهای خارجی خاصی را به آن اضافه کند.

خوشبختانه، گیتهاب به طرق مختلف بسیار قابل تنظیم است. در این بخش، نحوهٔ استفاده از سیستم هوکهای گیتهاب و API آن را بررسی میکنیم تا گیتهاب را مطابق خواستههایمان به کار بگیریم.

سرویسها و هوکها (Services and Hooks)

بخش هوکها و سرویسها در مدیریت مخزن گیتهاب سادهترین راه برای تعامل گیتهاب با سیستمهای خارجی است.

سرویسها (Services)

ابتدا نگاهی به سرویسها میاندازیم. هر دو نوع ادغام هوکها و سرویسها را میتوانید در بخش تنظیمات مخزن خود پیدا کنید؛ جایی که قبلاً افزودن همکاران و تغییر شاخه پیشفرض پروژه را بررسی کردیم. در تب «Webhooks and Services» چیزی شبیه Services and Hooks configuration section مشاهده خواهید کرد.

Services and Hooks configuration section
نمودار 129. Services and Hooks configuration section

دهها سرویس مختلف برای انتخاب وجود دارد که بیشتر آنها ادغام با سیستمهای تجاری و متنباز دیگر هستند. اکثر آنها برای خدمات یکپارچهسازی مداوم، ردیابهای اشکال و مسائل، سیستمهای چت گروهی و مستندسازی کاربرد دارند. ما با راهاندازی یک سرویس بسیار ساده، یعنی هوک ایمیل، پیش میرویم. اگر از منوی کشویی “Add Service” گزینه “email” را انتخاب کنید، صفحه تنظیمات مانند Email service configuration ظاهر میشود.

Email service configuration
نمودار 130. Email service configuration

در این حالت، اگر روی دکمه «Add service» کلیک کنیم، آدرس ایمیلی که مشخص کردهایم هر بار که کسی به مخزن پوش کند، ایمیلی دریافت خواهد کرد. سرویسها میتوانند به انواع مختلفی از رویدادها گوش دهند، اما بیشترشان فقط به رویدادهای پوش حساساند و سپس کاری با آن دادهها انجام میدهند.

اگر سیستمی دارید که میخواهید با گیتهاب ادغام کنید، ابتدا اینجا را بررسی کنید تا ببینید آیا ادغام سرویس موجود هست یا نه. برای مثال، اگر از Jenkins برای اجرای تستهای کد خود استفاده میکنید، میتوانید سرویس داخلی Jenkins را فعال کنید تا هر بار که کسی به مخزن شما پوش میکند، یک اجرای تست شروع شود.

هوکها (Hooks)

اگر به چیزی خاصتر نیاز دارید یا میخواهید با سرویسی یا سایتی که در این فهرست نیست ادغام کنید، میتوانید از سیستم عمومیتر هوکها استفاده کنید. هوکهای مخزن گیتهاب بسیار سادهاند. شما یک URL مشخص میکنید و گیتهاب در هر رویدادی که بخواهید، یک بارگذاری HTTP به آن URL ارسال میکند.

معمولاً این کار به این شکل انجام میشود که یک سرویس وب کوچک راهاندازی میکنید تا به بارگذاری هوک گیتهاب گوش دهد و سپس وقتی داده دریافت شد، کاری با آن انجام دهد.

برای فعالسازی یک هوک، روی دکمه “Add webhook” در Services and Hooks configuration section کلیک کنید. این شما را به صفحهای مانند Web hook configuration میبرد.

Web hook configuration
نمودار 131. Web hook configuration

تنظیمات یک وب هوک بسیار ساده است. معمولاً کافی است یک URL و کلید مخفی وارد کنید و روی “Add webhook” کلیک کنید. چند گزینه برای انتخاب رویدادهایی که میخواهید گیتهاب برایشان بارگذاری ارسال کند وجود دارد — پیشفرض این است که فقط بارگذاری برای رویداد push دریافت کنید، یعنی وقتی کسی کد جدیدی به هر شاخهای از مخزن شما پوش میکند.

بیایید یک مثال کوچک از سرویس وبی که ممکن است برای مدیریت یک وب هوک راهاندازی کنید ببینیم. ما از فریمورک وب Ruby به نام 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

اینجا، ما بارگذاری JSON را که گیتهاب ارسال میکند دریافت میکنیم و بررسی میکنیم چه کسی پوش کرده، به کدام شاخه پوش شده و چه فایلهایی در همهٔ کامیتهای پوش شده تغییر کردهاند. سپس آن را با معیارهای خود مقایسه میکنیم و اگر تطابق داشت، ایمیل ارسال میکنیم.

برای توسعه و آزمایش چنین چیزی، یک کنسول توسعهدهندهٔ خوب در همان صفحه راهاندازی هوک دارید. میتوانید آخرین چند بارگذاری که گیتهاب سعی کرده به آن هوک ارسال کند را ببینید. برای هر هوک میتوانید جزئیات زمان ارسال، موفقیتآمیز بودن، بدنه و هدرهای درخواست و پاسخ را بررسی کنید. این باعث میشود تست و اشکالزدایی هوکها بسیار آسان شود.

Web hook debugging information
نمودار 132. Web hook debugging information

ویژگی عالی دیگر این است که میتوانید هر یک از بارگذاریها را دوباره ارسال کنید تا سرویس خود را به راحتی آزمایش کنید.

برای اطلاعات بیشتر دربارهٔ نحوهٔ نوشتن وب هوکها و انواع مختلف رویدادهایی که میتوانید به آنها گوش دهید، به مستندات توسعهدهندگان گیتهاب در https://docs.github.com/en/webhooks-and-events/webhooks/about-webhooks مراجعه کنید.

API گیتهاب (The GitHub API)

سرویسها و هوکها به شما این امکان را میدهند که اعلانهایی دربارهٔ رویدادهای رخداده در مخازن خود دریافت کنید، اما اگر نیاز به اطلاعات بیشتری دربارهٔ این رویدادها داشته باشید چه؟ اگر بخواهید کارهایی مانند افزودن همکار یا برچسبگذاری مسائل را به صورت خودکار انجام دهید چه؟

در اینجا API گیتهاب به کمک شما میآید. گیتهاب تعداد زیادی نقطهٔ پایانی (endpoint) API دارد که تقریباً هر کاری را که میتوانید روی وبسایت انجام دهید به صورت خودکار امکانپذیر میکند. در این بخش یاد میگیریم چگونه احراز هویت کنیم و به API متصل شویم، چگونه روی یک مسئله نظر بگذاریم و چگونه وضعیت یک Pull Request را از طریق API تغییر دهیم.

استفادهٔ پایه (Basic Usage)

سادهترین کاری که میتوانید انجام دهید، درخواست 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"
}
 تعداد بسیار زیادی نقطه انتهایی (endpoint) مانند این وجود دارد که میتوانید از طریق آنها اطلاعات مربوط به سازمانها، پروژهها، مسائل، کامیتها — تقریباً هر چیزی که بهصورت عمومی روی گیتهاب قابل مشاهده است — را دریافت کنید.
حتی میتوانید از 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*
"
}

نظر دادن روی یک مسئله (Commenting on an Issue)

با این حال، اگر بخواهید عملی روی وبسایت انجام دهید، مانند نظر دادن درباره یک Issue یا Pull Request، یا اگر بخواهید محتوای خصوصی را مشاهده یا با آن تعامل کنید، باید احراز هویت کنید.

روشهای مختلفی برای احراز هویت وجود دارد. میتوانید از احراز هویت پایه تنها با نام کاربری و رمز عبور خود استفاده کنید، اما معمولاً بهتر است از یک توکن دسترسی شخصی استفاده کنید. میتوانید این توکن را از تب «Applications» در صفحه تنظیمات خود ایجاد کنید.

Generate your access token from the “Applications” tab of your settings page
نمودار 133. Generate your access token from the “Applications” tab of your settings page

از شما خواسته میشود که دامنههای دسترسی (scopes) مورد نیاز برای این توکن و توضیحی درباره آن را مشخص کنید. حتماً توضیح مناسبی بنویسید تا وقتی اسکریپت یا برنامه شما دیگر استفاده نشد، راحت بتوانید توکن را حذف کنید.

GitHub این توکن را فقط یک بار به شما نشان میدهد، پس حتماً آن را کپی کنید. اکنون میتوانید به جای استفاده از نام کاربری و رمز عبور، از این توکن برای احراز هویت در اسکریپت خود استفاده کنید. این روش خوب است چون میتوانید دامنههای دسترسی را محدود کنید و توکن قابل لغو است.

این روش مزیت دیگری هم دارد که محدودیت نرخ درخواست شما را افزایش میدهد. اگر احراز هویت نکنید، محدود به ۶۰ درخواست در ساعت خواهید بود. اما با احراز هویت میتوانید تا ۵۰۰۰ درخواست در ساعت ارسال کنید.

پس بیایید از این روش برای گذاشتن نظر روی یکی از Issues خود استفاده کنیم. فرض کنیم میخواهیم نظر روی یک Issue مشخص، مثلاً Issue شماره ۶، بگذاریم. برای این کار باید یک درخواست HTTP POST به آدرس repos/<user>/<repo>/issues/<num>/comments با توکنی که ایجاد کردیم، به عنوان هدر 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:"
}

حالا اگر به آن Issue بروید، میتوانید نظر موفقیتآمیز خود را مشاهده کنید.

A comment posted from the GitHub API
نمودار 134. A comment posted from the GitHub API

میتوانید با API تقریباً هر کاری که در وبسایت میتوانید انجام دهید، انجام دهید — ایجاد و تنظیم milestones، اختصاص دادن افراد به Issues و Pull Requests، ایجاد و تغییر برچسبها، دسترسی به دادههای commit، ایجاد commit و branch جدید، باز کردن، بستن یا ادغام Pull Requests، ایجاد و ویرایش تیمها، نظر دادن روی خطوط کد در یک Pull Request، جستجو در سایت و غیره.

تغییر وضعیت یک درخواست کشش (Changing the Status of a Pull Request)

یک مثال نهایی که بسیار مفید است اگر با Pull Requests کار میکنید، بررسی میکنیم. هر commit میتواند یک یا چند وضعیت (status) مرتبط داشته باشد و API وجود دارد که میتوانید این وضعیتها را اضافه یا بررسی کنید.

اکثر سرویسهای Continuous Integration و تست از این API استفاده میکنند تا بعد از push کردن، کد را تست کنند و سپس گزارش دهند که آیا commit مورد نظر همه تستها را گذرانده است یا خیر. شما همچنین میتوانید از این روش استفاده کنید تا بررسی کنید که آیا پیام commit به درستی فرمت شده، آیا ارسالکننده همه دستورالعملهای مشارکت را رعایت کرده، آیا commit به درستی امضا شده — هر تعداد چیز دیگر.

فرض کنید یک webhook روی مخزن خود تنظیم کردهاید که به یک سرویس وب کوچک ضربه میزند و بررسی میکند که آیا در پیام commit عبارت «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

امیدوارم این موضوع نسبتاً ساده باشد. در این webhook handler، هر commit که تازه push شده را بررسی میکنیم، به دنبال عبارت «Signed-off-by» در پیام commit میگردیم و در نهایت با یک درخواست HTTP POST به endpoint /repos/<user>/<repo>/statuses/<commit_sha> وضعیت را ارسال میکنیم.

در این حالت میتوانید یک state ('success'، 'failure'، 'error')، توضیحی درباره اتفاقی که افتاده، یک URL هدف که کاربر میتواند برای اطلاعات بیشتر به آن مراجعه کند و یک «context» ارسال کنید تا اگر برای یک commit چند وضعیت وجود داشت، آنها از هم متمایز شوند. برای مثال، یک سرویس تست ممکن است یک وضعیت ارائه دهد و یک سرویس اعتبارسنجی مانند این نیز وضعیت دیگری بدهد — فیلد «context» برای تمایز بین آنهاست.

اگر کسی یک Pull Request جدید در GitHub باز کند و این webhook تنظیم شده باشد، ممکن است چیزی شبیه Commit status via the API ببینید.

Commit status via the API
نمودار 135. Commit status via the API

اکنون میتوانید یک علامت تأیید سبز کوچک کنار commit که در پیام آن عبارت «Signed-off-by» وجود دارد ببینید و یک علامت ضربدر قرمز روی آن که نویسنده فراموش کرده امضا کند. همچنین مشاهده میکنید که Pull Request وضعیت آخرین commit روی شاخه را گرفته و اگر آن وضعیت failure باشد به شما هشدار میدهد. این بسیار مفید است اگر از این API برای نتایج تست استفاده میکنید تا به اشتباه چیزی را که آخرین commit آن تستها را رد کرده، ادغام نکنید.

کتابخانه رسمی گیت‌هاب (Octokit)

اگرچه در این مثالها تقریباً همه کارها را با curl و درخواستهای ساده HTTP انجام دادهایم، چندین کتابخانه متنباز وجود دارد که این API را به شکلی طبیعیتر در اختیار شما قرار میدهند. در زمان نگارش این متن، زبانهای پشتیبانی شده شامل Go، Objective-C، Ruby و .NET هستند. برای اطلاعات بیشتر به https://github.com/octokit مراجعه کنید، زیرا این کتابخانهها بخش عمدهای از کارهای HTTP را برای شما مدیریت میکنند.

امیدوارم این ابزارها به شما کمک کنند تا GitHub را بهتر و متناسب با جریان کاری خاص خودتان سفارشی کنید. برای مستندات کامل تمام API و راهنمایی برای کارهای معمول، به https://docs.github.com/ مراجعه کنید.

scroll-to-top